diff --git a/InterfaceCEREMA/AperoDeDenis-3.14-1.x86_64.rpm b/InterfaceCEREMA/AperoDeDenis-3.14-1.x86_64.rpm new file mode 100644 index 0000000..943e5f0 Binary files /dev/null and b/InterfaceCEREMA/AperoDeDenis-3.14-1.x86_64.rpm differ diff --git a/InterfaceCEREMA/AperoDeDenis-5.0-amd64.msi b/InterfaceCEREMA/AperoDeDenis-5.0-amd64.msi new file mode 100644 index 0000000..93dbd6e Binary files /dev/null and b/InterfaceCEREMA/AperoDeDenis-5.0-amd64.msi differ diff --git a/InterfaceCEREMA/AperoDeDenis-5.0-win32.msi b/InterfaceCEREMA/AperoDeDenis-5.0-win32.msi new file mode 100644 index 0000000..5c8a673 Binary files /dev/null and b/InterfaceCEREMA/AperoDeDenis-5.0-win32.msi differ diff --git a/InterfaceCEREMA/AperoDeDenis.py b/InterfaceCEREMA/AperoDeDenis.py index dd5b7e7..0f6aee8 100644 --- a/InterfaceCEREMA/AperoDeDenis.py +++ b/InterfaceCEREMA/AperoDeDenis.py @@ -2,10 +2,95 @@ # -*- coding: utf-8 -*- # PEP 0008 -- Style Guide for Python Code -#ajout le 7/10 : second item de qualité des photos - -import tkinter # gestion des fenêtre, des boutons ,des menus +# Version 3 ou plus +# est-il possible de relancer Malt en conservant le niveau de zoom déjà atteint ??? pas sur, sauf en passant par Micmac + +# Version 2.35 : +# le 26 avril 2016 +# - affichage des heures avec les secondes +# - Controle que le nom du répertoire bin de micmac ne comporte pas d'espace. +#v 2.41 +# correction d'un bogue sur la suppression des points gps +# autorise 30 points gps +# 2.42 +# suppression bogue suppression de points gps multiples +# gcpbascule aprés tapas ET toujours avant malt +# 2.43 +# les conséquences du choix de nouvelles photos sont modifiées de trois façons : +# - si des emplacements de points GPS doivent être supprimés alors il y a demande à l'utilisateur +# - le nettoyage du chantier est moins brutal : les fichiers exp (exports) et ply sont conservés. +# - le chantier est enregistré avant de rendre la main (si l'utilsiateur ne validait pas un enregistrement ultérieur le chantier devenait inaccessible) +# ajout de import tkinter.messagebox pour le message d'avertissement si AperoDeDenis est dèjà lancé sous windows +# 2.44 +# Accepte les virgules comme séparateur décimal pour les points gps : remplacement des virgules saisies dans les coordonnées gps par des points +# 2.45 +# accepte la virgule pour la distance de la calibration métrique (remplace virguule par point) +# nouveau bouton : lance la calibration gps +# +# ajout de tawny après Malt, avec saisie libre des options (mosaiquage du résultat de malt/ortho) +# 2.50 +# Active/désactive le tacky message de lancement +# 2.6 +# saisie de l'incertitude sur la position des points GPS +# 2.61 +# correction d'un bogue de compatibilité ascendante (changement de structure de la liste des points gps. Le 14/09/2016 + +# a faire : corriger le mode d'obtention de ALL ou Line dans le calcul des indices de qualité +# toutes les focales : la commande explore les sous-répertoires comportant la chaine JPG !!! +# v 3.00 : bilingue (début novembre 2016) +# V 3.10 : sélection des meilleures photos +# v 3.11 : sélection des meilleurs images pour créer un nouveau chantier +# v 3.12 : correction bogue affichage gps +# v 3.13 : recherche exiftool et convert sous binaire-aux\windows ffmpeg absent sous bin; +# possibilité de saisir une unité avec la distance +# controle des photos supprimé si lanceMicMac aprés Tapas. +# v 3.14 : correction d'une régression de la v 3.13 lors de la restauration des paramètres (dûe à l'ajout de self.ffmpeg dans la sauvegarde). +# v 3.20 : les photos autour de la maitresse pour Malt ne sont plus "autour" mais choisies parmi les meilleures en correspondances +# Ajout d'un choix pour Malt : AperoDeDenis, l'interface recherche les maitresses et les photos correspondantes +# ajout filtre pour afficher l'erreur max sur gcpbascule (erreur positionnement des points GPS. +# controle affiné des points gps : on indique ceux qui ne sont placés sur une seule photo et on vérifie la présence de 3 points sur 2 photos +# aprés plantage durant malt ou fusion : on renomme les JPG et les PLY lors du rédémarrage (reste pb semblable pour calibration intrinsèque) +# suppression d'un point GPS sur une photo (avant : suppression de tous les points) +# Affichage dans l'état du chantier des points GPS positionnés sur une seule photo +# Non mise dans le xml des points gps positionnés une seule fois. +# Si le controle des points GPS est négatif alors les fichiers xml ne sont pas créés +# 3.30 +# 1) créer une mosaique aprés tapas sur toutes les photos : "Tarama" ".*.JPG" "Arbitrary" +# 2) la mosaïque est un tif : sour le répertoire TA : TA_LeChantier.tif +# 3) saisir un masque sur la mosaïque créée : par l'outil de saisie de masque, la masque doit s'appeler : +# Les masques sont pris en compte par défaut ou si l’option DirTA = "TA" et UseTA=1 de Malt sont actives. (UseTA = 1 par défaut) +# Par défaut l’ajout est _Masq, qui peut être modifiée avec l’option MasqIm de Malt. ( "_Masq" après le nom) +# un fichier xml accompagne le masque (créé par MicMac ?) +# voir description : http://jmfriedt.free.fr/lm_sfm.pdf +# 4) Lancer Malt option Ortho : "C:/MicMac6706/bin\mm3d.exe" "Malt" "Ortho" ".*.JPG" "Arbitrary" "NbVI=2" "ZoomF=4" DirTA=TA +# 5) Lancer Tawny pour créer une mosaïque sur le résultat de malt : "mm3d" "Tawny" "Ortho-MEC-Malt/" : +# ce qui donne la mosaique Orthophotomosaic.tif sous le répertoire "Ortho-MEC-Malt/" +# 6) lancer Nuage2Ply pour obtenir le ply sous le répertoire Mec-Malt : NuageImProf_STD-MALT_Etape_7.ply +# C:\Python340\MesScripts\AperoDeDenis\vaches noires\micmac_17>mm3d Nuage2Ply Mec-Malt/NuageImProf_STD-MALT_Etape_7.xml Attr=Ortho-MEC-Malt/Orthophotomosaic.tif +# 7) vérifier si une nouvelle version est disponible +# 8) faire un masque "inverse" ou multiple ok +# 9) ouvrir les mosaiques par menu +# menu expert : exécuter une ligne de commande +# correction : self.e au lieu de e dans MyDialog +# version 3.31 +# copier les points gps d'une chantier dans un autre (en corrigeant ce qu'il faut, menu expert) +# version 3.32 : 2 corrections mineures (lignes 3854 supprimée et 3953 orthographe) +# Version 3.33 : correction comptage des points GPS et des points GPS avec les mêmes coordonnées ( définition de listePointsActifs revue) +# Version 3.34 : janvier 2018 +# correction de : e remplacé par self.e dans MyDialog (fixe le problème du renommage des chantiers) +# ajout de self.pasDeFocales = False aprés la mise à jour des exifs. (fixe le problème du message erroné concerné les focales manquantes) +# modification de l'icone de la fenêtre = l'icone du cerema remplace le graindsel. +# possibilité de choisir le ménage : suppression totale ou conservation des résultats seuls +# Affichage du gain de place en MO aprés le ménage +# affichage de la taille du dossier en MO dans l'affichage de l'état du chantier +# test de la présence de sous répertoire dans afficheetat : +# si etatChantier>2 et pas de sous-répertoire alors etatChantier remis à 2 et +# message "chantier nettoyé" affiché +# la version 3.34 est rebaptisée 5.0 (suppression de l'item "indice surfacique") + +from tkinter import * # gestion des fenêtre, des boutons ,des menus import tkinter.filedialog # boite de dialogue "standards" pour demande fichier, répertoire +import tkinter.messagebox # pour le message avertissant que AperoDeDenis est déjà lancé import tkinter.ttk as ttk # amélioration de certains widgets de tkinter : le comportement est géré indépendamment de l'apparence : c'est mieux ! mais différent ! import pickle # pour la persistence import os.path # pour les noms de fichier @@ -20,13 +105,474 @@ from PIL import ImageDraw import base64 import tempfile +import inspect +import zipfile +import zlib +import ctypes +import gettext +import urllib.request +import webbrowser +import threading + + + +'''################################################################################ +# Librairies utilisées pour le module de calcul des indices surfaciques # +################################################################################ + +import math # Pour utiliser la fonction racine carrée +import csv # Pour la lecture de la grille à partir du fichier +import numpy as np +from scipy.interpolate import griddata # Pour l'interpolation +import matplotlib.pyplot as plt # Pour l'affichage des profils utilisés +from mpl_toolkits.mplot3d import Axes3D # Pour l'affichage des surfaces +from matplotlib import cm # Pour choisir la couleur de des surfaces lors de l'affichage''' + +################################## Classe : Choix de la langue en cas d'absence dans les paramètres ###########################" + + +def foreach_window(hwnd, lParam): + if IsWindowVisible(hwnd): + length = GetWindowTextLength(hwnd) + buff = ctypes.create_unicode_buffer(length + 1) + GetWindowText(hwnd, buff, length + 1) + titles.append(buff.value) + return True + +def heure(): # time.struct_time(tm_year=2015, tm_mon=4, tm_mday=7, tm_hour=22, tm_min=56, tm_sec=23, tm_wday=1, tm_yday=97, tm_isdst=1) + return ("le %(jour)s/%(mois)s/%(annee)s à %(heure)s:%(minutes)s:%(secondes)s") % {"jour" : str(time.localtime()[2]), "mois" : str(time.localtime()[1]), "annee" : str(time.localtime()[0]), "heure" : str(time.localtime()[3]), "minutes" : str(time.localtime()[4]), "secondes": str(time.localtime()[5])} + +def fin(codeRetour=0): + os._exit(codeRetour) + +class InitialiserLangue(tkinter.Frame): + def __init__(self, frame, **kwargs): + self.frame = tkinter.Frame + self.frame.__init__(self, frame, **kwargs) + frame.geometry("400x200") + photo = tkinter.PhotoImage(data=iconeTexte) + frame.tk.call('wm', 'iconphoto', frame._w, photo) + self.pack(fill=tkinter.BOTH) + frame.title("") + global langue + langue = "NA" + + self.message = tkinter.Label(self, text="Choisissez une langue\nSelect your language") + self.message.pack() + + self.bouton_francais = tkinter.Button(self, text = "Français/French", command = self.langueFrancaise) + + self.bouton_anglais = tkinter.Button(self, text = "Anglais/English", command = self.langueAnglaise) + self.bouton_francais.pack(side = tkinter.LEFT) + self.bouton_anglais.pack(side = tkinter.RIGHT) + + frame.protocol("WM_DELETE_WINDOW", self.arret) + + def arret(self): + frame.destroy() + print("Fermeture inatendue de la fenêtre / Unexpected closure of the window") + sys.exit() + + + def langueFrancaise(self): + global langue + langue = "fr" + frame.destroy() + + + def langueAnglaise(self): + global langue + langue = "en" + frame.destroy() + + +################################# Outils de traduction ###################################################### +def chargerLangue(): + try: + sauvegarde2 = open(os.path.join(repertoire_data, "ParamMicmac.sav"),mode='rb') + r2=pickle.load(sauvegarde2) + sauvegarde2.close() + langue = r2[9] + return(langue) + + except Exception as e: + return "null" + + +################################## INITIALISATION DU PROGRAMME ########################################################### + +# Variables globales + +numeroVersion = "5.0" +version = " V "+numeroVersion # conserver si possible ce format, utile pour controler +continuer = True # si False on arrête la boucle de lancement de l'interface +messageDepart = str() # Message au lancement de l'interface +compteur = 0 # Compte le nombre de relance de l'interface +iconeTexte = "R0lGODlhIAAgAIcAMfr8+EqrpcfLEe16CJnE1Lnb3Hm7whaXjuzdu+VLEp64HuiRL9TYVfPImeqoU4e1NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIAAgAAcI/gABCBxIEACCgwgENliYsKDDhwMVKHjwQOCAiwMgaiwoUaLABRgbboSIYKLEhCAvNhipkUFHBQwAOMC4gOVDBAI6CoiJAOMAkTYFMhCQUwHRjzSDDhxK1CjRmA18OlDKlKjVozKlssR5VQCAqzEBpLy4YGXBgwyqWk2oNmFPnwMWOGjQsOvVhAUCdHU7NoFfvwnt7hSYN4CBvQCi/l0cGGxDAgEiB3jQte/iBGzTiixgQHLkAlxnwh3A2CFnz5EJCB1L0wFQAAViE+iM2nABpD7LPixwoHdvw5INGJhNgPUAs7AJKFfN27dv28tnP6DZsMDs4cphO39+GwBx5TNrcCbHHl1ggOeeVXtfbmABXvLf1Q887bk7+9uc2RPoDhFyfdjkWXefTYVFZoBA7AUwYFAFKgggZAcMZwB/QflnGIKdRbifUgT9x9lv8nHonWTMnXdAABRyWOCBCJiIoogdSiaQczASJJxw5slY444DBQQAOw==" +versionInternet = str() # version internet disponible sur GitHub, "" au départ + +# recherche du répertoire d'installation de "aperodedenis" (différent suivant les systèmes et les versions de système) + +repertoire_script=os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0])) +if not os.path.isdir(repertoire_script): + repertoire_script = os.path.dirname(os.path.abspath(__file__)) +if not os.path.isdir(repertoire_script): + repertoire_script = os.path.dirname(sys.argv[0]) +if not os.path.isdir(repertoire_script): + repertoire_script = os.getcwd() +if not os.path.isdir(repertoire_script): + repertoire_script = os.getcwd() + +if os.name=="nt": + + # lancement unique d'aperodedenis sous WINDOWS : (pas trouvé d'équivalent sous Linux/Ubuntu) + # liste des fenetres sous windows, pour éviter de relancer l'appli si déjà lancée + EnumWindows = ctypes.windll.user32.EnumWindows + EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) + GetWindowText = ctypes.windll.user32.GetWindowTextW + GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW + IsWindowVisible = ctypes.windll.user32.IsWindowVisible + titles = [] + EnumWindows(EnumWindowsProc(foreach_window), 0) # liste des fenetres ouvertes dans titles + + # apero déjà ouvert ? + liste = [e for e in titles if "AperoDeDenis V "in e] + if liste.__len__(): + texte = "AperoDeDenis est déjà lancé dans la fenêtre :\n\n"+liste[0]+"\n\n"+\ + "La version actuelle d'AperoDeDenis n'autorise qu'une seule instance du programme.\n"+\ + "Valider pour quitter." + tkinter.messagebox.showwarning("AperoDeDenis : Avertissement",texte) + fin() + # Répertoire de travail + + repertoire_data = os.path.join(os.getenv('APPDATA'),'AperoDeDenis') + try: os.mkdir(repertoire_data) + except: pass + if not os.path.isdir(repertoire_data): + repertoire_data = repertoire_script + langue = chargerLangue() + if (langue != "en" and langue != "fr"): + frame = tkinter.Tk() + initialiserLangue = InitialiserLangue(frame) + initialiserLangue.mainloop() + + +else: # sous Linux + + if not os.path.isdir(repertoire_script): + repertoire_script = os.getenv('HOME') + repertoire_data = repertoire_script + try: os.mkdir(repertoire_data) + except: pass + if not os.path.isdir(repertoire_data): + repertoire_data = repertoire_script + langue = chargerLangue() + if(langue != "en" and langue != "fr"): + frame = tkinter.Tk() + initialiserLangue = InitialiserLangue(frame) + initialiserLangue.mainloop() +repertoire_langue = os.path.join( repertoire_script, 'locale') +try: + traduction = gettext.translation('AperoDeDenis', localedir = repertoire_langue, languages=[langue]) + traduction.install() +except: + def _(a=str(),b=str()): + return a+b + + +# Message indiquant le lancement de l'outil dans le shell + +print(heure()+_(" lancement d'aperodedenis")+version+".") + + +############################ FIN DE L'INITIALISATION ######################################################### + +################################################################################ +# Classes pour le calcul d'indices de surfaces # +################################################################################ + + +################# Passge du fichier .ply aux coordonnées xyz ################### +class Ply2XYZ(): + def __init__(self, **kwargs): + endian = "@" # valeur par défaut : endian du système + fmt = str() # format de codage des données dans le ply ce format est utilisé par struct + i = int() + self.fichierPly = tkinter.filedialog.askopenfilename( + filetypes=[("Ply","*.ply"),(_("Tous"),"*")],multiple=False, + title = _("Ply à lire")) # choix du fichier + if self.fichierPly==str(): # si pas de fichier choisi par l'utilisateur : on quitte + return + print(_("Fichier à lire : "),self.fichierPly) + with open(self.fichierPly, 'rb') as infile: # lecture du fichier en mode "binaire" + ligne = infile.read() + + lignes =ligne.splitlines() # coupure du flux bianire en "lignes" + if lignes[0]!=b'ply': # vérification que le tag "ply" est présent en entête de fichier + print(_("Il ne s'agit pas d'un fichier ply issu de MicMac !")) + return # Abandon si pas fichier ply + self.fichierPlyXYZ = os.path.splitext(self.fichierPly)[0]+".xyz"# nom du fichier xyz qui sera écrit + print(_("Fichier à écrire : "),self.fichierPlyXYZ) # information sur le nom du fichier + for e in lignes: # décodage des lignes d'entête qui indique la structure du fichier + i+=1 + if e==b'end_header': + break # tag de fin d'entête on connait la structure, fin du décodage de la structure + s=str(e) + if "little_endian" in s: # boutisme + endian="<" + if "big_endian" in s: + endian=">" + if "element vertex" in s: # nombre de points + nombre_points = int(s.split(" ")[-1][0:-1]) + print(_("nombre de points : "),str(nombre_points)) + if "property" in s: # property : liste les éléments de la structure des données pour chaque point + if s.split(" ")[1]=="float": # Micmac n'utilsie que les valeurs float et uchar + fmt += "f" # indique qu'il y a un float à lire + elif s.split(" ")[1]=="uchar": + fmt += "B" # indique qu'il y a un octet à lire + elif s.split(" ")[1]!="list": # la valeur list est aussi utilisée, s'il s'agit d'une autre valeur : abandon + print("format non prévu pour les ply issus de micmac, abandon : ",s.split(" ")[1]) + return + print("ligne ",str(i)," : ",e) + if fmt!="fffBBB": # il doit y avoir trois flottant (x,y,z) et 3 octets (Rouge, vert, bleu) sinon pas MicMac + print(_("Le format des données indique qu'il ne s'agit pas d'un ply généré par MicMac. Le format trouvé est : "),fmt,_(" le format attendu est : fffBBB")) + return + fmt = endian+fmt # le format est complété par le boutisme + print(_("Longueur du fichier : "),str(ligne.__len__())) + print(_("format du fichier > = big_endian, < = little_endian :"),endian) + print(_("Format des données : "),fmt,_(" longueur : "),str(struct.calcsize(fmt))) + + print(_("patience : écriture du fichier xyz en cours")) + debutData = ligne.find(b"end_header",0,1000)+11 # on extrait la zone des données utiles dans la varible "ligne" : début = aprés l'entête + longueurData = nombre_points*struct.calcsize(fmt) # on prend juste la longueur nécessaire (nombre de point * longueur des données du point) + finData = debutData + longueurData + plageData = ligne[debutData:finData] # extraction + print(_("Plage des données : début = "),str(debutData),_(" fin = "),str(finData),_(" longueur = "),str(longueurData)) + try: + lesXYZ = [(str(x),str(y),str(z)) for (x,y,z,r,v,b) in struct.iter_unpack(fmt,plageData).__iter__() ] # list comprehension extrayant les xyz de la structure décodée + except Exception as e: + print(_("Erreur lors du décodage des données, le ply ne provient pas de micmac. Erreur : "),e) + return + with open (self.fichierPlyXYZ,"w") as outfile: # ouverture du fichier de sortie + for e in lesXYZ: # pour chaque élément de la liste des xyz + outfile.write(" ".join(e)+"\n") # écriture des éléments x y et z séparé par un espace (si on veut une virgule mettre "," au lieu de " " + print("Fichier %s écrit sur disque") % (self.fichierPlyXYZ) # message final + def fname_out(self): + return os.path.splitext(self.fichierPly)[0]+".xyz" + +####################### Création de grille régulière ########################### + +class Grille(object): + + # Constructeur + def __init__(self): + self.nom= _("nom du fichier contenant les données : à déterminer") + + # accesseurs // property + def _set_nom(self, nomFichier): + self.nom = nomFichier + + def _get_nom(self): + return self.nom + + #Méthodes + #création de la grille régulière + + def creer_grille(self,methode,step): + mat = np.genfromtxt(self._get_nom(), delimiter=' ') + points = mat[:,:2] + values = mat[:,2] + # les limites (x,y) de mes données + + min_x = min(mat[:,0]) + max_x = max(mat[:,0]) + + min_y = min(mat[:,1]) + max_y = max(mat[:,1]) + # générer un maillaige avec un pas régulier, création de la grille régulière + + grid_x, grid_y = np.mgrid[min_x:max_x+step:step, min_y:max_y+step:step] + grid_z = griddata(points, values, (grid_x, grid_y), method=methode, fill_value=-9999) + return grid_z + + def affiche_grille(self, methode, step): + + mat = np.genfromtxt(self._get_nom(), delimiter=' ') + points = mat[:,:2] + values = mat[:,2] + # les limites (x,y) de mes données + + min_x = min(mat[:,0]) + max_x = max(mat[:,0]) + + min_y = min(mat[:,1]) + max_y = max(mat[:,1]) + + # générer un maillaige avec un pas régulier, création de la grille régulière + grid_x, grid_y = np.mgrid[min_x:max_x+step:step, min_y:max_y+step:step] + grid_z = griddata(points, values, (grid_x, grid_y), method=methode) + # Création du modèle 3D : Axes, légende, couleur... + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + ax.plot_surface(grid_x, grid_y, grid_z, cmap=cm.coolwarm) + ax.set_title(methode+_(" pas du maillaige : ")+str(step)) + ax.set_xlabel('X Label') + ax.set_ylabel('Y Label') + ax.set_zlabel('Z Label') + plt.show() + return + + #sauvegarder_grille dans un fichier + def sauvegarder_grille(self, obj, grille, step): + return np.savetxt(os.path.splitext(obj.fichierPly)[0]+'_regular_'+str(step).replace(".","")+'.txt',grille, fmt='%.18e', delimiter=' ', newline='\r\n', header='') + # Récupérer le nom du fichier de la grille + def nomFichier_sortie(self, obj, step): + return os.path.splitext(obj.fichierPly)[0]+'_regular_'+str(step).replace(".", "")+'.txt' + +################## Manipulation des données et traitement ###################### + +class Conteneur(object): + + # Constructeur + def __init__(self): + self.nom = _("nom du fichier contenant les données : à déterminer") + + + # accesseurs // property + def _set_nom(self, nomFichier): + self.nom = nomFichier + def _get_nom(self): + return self.nom + + + # Méthodes + def charger_data(self): # on ne charge pas les points avec -9999 comme valeur (correspond à nan) + fname = open(self._get_nom()) + lignes = csv.reader(fname, delimiter=' ') + hauteurs = {} + cle = 1 + for line in lignes: + valeur = [float(i) for i in line[:len(line)-1] if float(i) != -9999] # chaque ligne est une liste, on ne prend que les valeurs différentes de -9999 + if(len(valeur) != 0): + hauteurs[cle] = valeur + else : + hauteurs[cle] = None # si valeur est vide on lui donne None comme valeur + cle += 1 + fname.close() + return hauteurs + + def charger_all(self): # on prend toutes les valeurs + fname = open(self._get_nom()) + lignes = csv.reader(fname, delimiter=' ') + hauteurs = {} + cle = 1 + for line in lignes: + valeur = [float(i) for i in line[:len(line)-1] ] + hauteurs[cle] = valeur + cle += 1 + fname.close() + return hauteurs + + #calcul de la moyenne des valeurs d'un tableau + def moyenne(self, tab): + return sum(tab)/len(tab) + + # Moyenne de l'écart type des hauteurs = Rq = rugosité moyenne quadratique + def ecart_type(self): + hauteurs = self.charger_data() + valeur = [] # On stocke Rq de chaque profil dans cette liste + for val in hauteurs.values(): + if(val != None): + mean = self.moyenne(val) + temp = list(map(lambda x : x*x, [(i-mean) for i in val])) + valeur.append(math.sqrt(self.moyenne(temp))) + rugo = self.moyenne(valeur) # on fait la moyenne des Rq + epsilon = math.sqrt(sum(list(map(lambda x : x*x, [(i-rugo) for i in valeur])))/len(valeur)) # Ecart-type des Rq + return [rugo, epsilon] + + # pmp_profil : profondeur moyenne de profil + def pmp_profil(self, profil, tableau): + pivot = int(len(profil)/2) + pic1 = max(profil[:pivot+1]) # le plus haut pic dans la 1ére moitié du profil + pic2 = max(profil[pivot+1:]) # le plus haut pic dans la 2éme moitié du profil + resultat = 0.5*(pic1+pic2) - self.moyenne(tableau) # Moyenne des 2 pics - profil moyen + return resultat + + # pmp + def pmp(self): + tableau_val =[] + keys = [] + hauteurs = self.charger_all() # Dictionnaire avec toutes les valeurs + for cle in range(1, len(hauteurs)+1) : + profil = hauteurs.get(cle) + taux = profil.count(-9999)/len(profil) + if ( taux < 0.2): # On ne prend pas les profils avec plus de 20% (de -9999) de l'information contenue dans profil + keys.append(cle) + work = [x for x in profil if x != -9999] # cle = identifiant du profil (utilisé pour l'affichage des profils utilisés) + tableau_val.append(self.pmp_profil(profil,work)) # On stocke les pmp de chaque profil dans un tableau + moyenne_pmp = self.moyenne(tableau_val) # Moyenne des pmp + epsilon = math.sqrt(sum(list(map(lambda x : x*x, [(i-moyenne_pmp) for i in tableau_val])))/len(tableau_val)) # Ecart-type des pmp + return [moyenne_pmp, epsilon, keys] + + # tortuosité de profil : longueur réelle du profil / la longeur entre les extrémités + def tortuosity_profil(self,pas,tableau): + j = len(tableau)-1 # Dans cette méthode on ne prend pas en compte les cellules où on a -9999 + i = 0 + while(tableau[j] == -9999 or tableau[i] == -9999): + if(tableau[j] == -9999) : + j -= 1 + if(tableau[i] == -9999): + i += 1 + calc_inter = (tableau[j]-tableau[i])**2 + (pas*(j - i))**2 # (y1-y2)**2+(x1-x2)**2 + longueur_extremit = math.sqrt(calc_inter) # Distance euclidienne + longueur_profil = 0 + while(i < j): + l = i + 1 + while(tableau[l] == -9999): + l += 1 + temp = (tableau[l]-tableau[i])**2 + (pas*(l-i))**2 + longueur_profil += math.sqrt(temp) + i = l + return longueur_profil/longueur_extremit + + # tortuosité + def tortuosity(self, pas): + tortuosite = [] + keys = [] + hauteurs = self.charger_all() + for cle in range(1,len(hauteurs)+1): + profil = hauteurs.get(cle) + taux = profil.count(-9999)/len(profil) + if (taux < 0.2): + keys.append(cle) # cle = identifiant du profil (utilisé pour l'affichage des profils utilisés) + tortuosite.append(self.tortuosity_profil(pas,profil)) # On stocke la tortuosité de chaque profil dans un tableau + epsilon = math.sqrt(sum(list(map(lambda x : x*x, [(i-self.moyenne(tortuosite)) for i in tortuosite])))/len(tortuosite)) # Ecart-type des tortuosité + return [self.moyenne(tortuosite), epsilon, keys] + # Afficher un profil utilisé dans les calculs de : PMP, Tortuosité + def affiche_profil(self, cle, step): + def nan(x): + if(x== -9999): + x = 0 + return x + hauteurs = self.charger_all() + profil = [nan(x) for x in hauteurs.get(cle) ] + x = np.array([i*step for i in range(len(profil))]) + profil = np.array(profil) + plt.plot(x, profil, label=_("profil n°")+str(cle)) + plt.legend() + plt.show() + return + +########################### Variables globales 2 ################################# +#donnee = Conteneur() +#grid = Grille() ########################### Classe pour tracer les masques class TracePolygone(): - def __init__(self, fenetre, image, masque,labelBouton='Tracer le masque'): # fenetre : root de l'appli ; image : fichier image sur lequel tracer le polygone ; masque = nom du fichier à créer + def __init__(self, fenetre, image, masque,labelBouton=_('Tracer le masque')): # fenetre : root de l'appli ; image : fichier image sur lequel tracer le polygone ; masque = nom du fichier à créer self.root = tkinter.Toplevel() #fenêtre spécifique à la saisie du masque - self.root.title("Saisie sur la photo : "+image) # titre + self.root.title(_("Saisie sur la photo : ")+image) # titre fenetreIcone(self.root) self.root.geometry( "900x900" ) # Taille self.dimMaxiCanvas = 600 # dimension max du canvas accueillant l'image @@ -36,8 +582,8 @@ def __init__(self, fenetre, image, masque,labelBouton='Tracer le masque'): # fe self.listePointsJPG = list() # liste des points du polygone self.polygone = False # deviendra vrai lorsque le polygone sera effectif self.file = image # nom du fichier partagé, devient attribut de la classe - self.nomMasque = masque # nom du fichier masque partagé (en principe : os.path.splitext(self.file)[0]+"_mask.tif") - + self.nomMasque = masque # nom du fichier masque partagé (en principe : os.path.splitext(self.file)[0]+"_Mask.tif") + self.inverse = False #pour inverser le masque : intervertit l'intérieur et l'extérieur # initialisations de l'affichage de l'image, dimensions du cadre, positionnement : self.imageFichier = Image.open(self.file) # ouverture de la photo @@ -75,18 +621,20 @@ def __init__(self, fenetre, image, masque,labelBouton='Tracer le masque'): # fe self.root.bind("a",self.delete) self.frame2 = ttk.Frame(self.root, borderwidth = 2,relief = 'sunken') # cadre pour la photo et les boutons - self.boutonQuitter = ttk.Button(self.frame2, text="Valider",command = self.quitter) - self.boutonAbandon = ttk.Button(self.frame2, text="Abandon",command = self.abandon) + self.boutonInverser = ttk.Button(self.frame2, text=_("Inverser"),command = self.inverser) + self.boutonQuitter = ttk.Button(self.frame2, text=_("Valider"),command = self.quitter) + self.boutonAbandon = ttk.Button(self.frame2, text=_("Abandon"),command = self.abandon) self.boutonTracer = ttk.Button(self.frame2, text=labelBouton,command = self.tracerMasqueBis) self.boutonAide = ttk.Label (self.frame2, - text= "\nmolette de la souris = zoom,\n"+\ - "utilisable avant ET pendant le tracé\n"+\ - "glisser-déposer actif avant le tracé\n\n"+\ - "Tracer :\n"+\ - "Clic gauche : ajouter un point;\n clic droit : fermer le polygone,\n"+\ - "Touche Del pour supprimer un point ou le polygone,\n") + text= "\n" + _("molette de la souris = zoom,") + "\n"+\ + _("utilisable avant ET pendant le tracé") + "\n"+\ + _("glisser-déposer actif avant le tracé=") + "\n\n"+\ + _("Tracer :") + "\n"+\ + _("Clic gauche : ajouter un point;\n double clic gauche : fermer le polygone,") +"\n"+\ + _("Touche Del pour supprimer un point ou le polygone,") + "\n") self.boutonAide.pack(side='left',pady=2,padx=2) self.boutonTracer.pack(side='left',pady=2,padx=8) + self.boutonInverser.pack(side='left',pady=2,padx=8) self.boutonQuitter.pack(side='left',pady=2,padx=8) self.boutonAbandon.pack(side='left',pady=2,padx=8) self.frame2.pack() @@ -96,7 +644,9 @@ def __init__(self, fenetre, image, masque,labelBouton='Tracer le masque'): # fe self.root.grab_set() fenetre.wait_window(self.root) - def quitter(self): # libère les ressources images pour ne pas les "bloquer" + def quitter(self): + # libère les ressources images pour ne pas les "bloquer" + try: self.imageFichier.close() except: pass try: self.imageMasque.close() @@ -158,7 +708,7 @@ def b1Double(self,event): # pour clore la poly if event.widget!=self.canvas: return # si le clic n'est pas sur l'image (canvas=frame=image) on ne fait rien if self.frame.cget("cursor").string=="plus": # le cursor "plus" indique l'ajout d'un point : on clot if self.listePointsJPG.__len__()<=1: #polygone avec trop peu de point - self.infoBulle(event,"Il faut au moins 2 points dans le polygone.") + self.infoBulle(event,_("Il faut au moins 2 points dans le polygone.")) return self.tracerMasqueBis() # on désactive le bouton de tracé self.afficherPolygone() @@ -188,7 +738,7 @@ def moletteLinux5(self,event): # l'utilisateur Linu def redrawZoom(self, event): # l'utilisateur zoom avant avec la molette de la souris : mémo du zoom précédent if self.scale>self.maxScale: # si l'échelle passe à plusieurs pixels écran pour un pixel image on arrête - self.infoBulle(event,texte="Zoom maximum atteint") # l'utilisateur est informé + self.infoBulle(event,texte=_("Zoom maximum atteint")) # l'utilisateur est informé return self.listeSauveImages.append((self.xNW,self.yNW,self.xSE,self.ySE,self.img,self.scale)) # sauvegarde pour retour arrière (redrawDeZoom) self.positionNouveauZoom(event.x,event.y) # calcule les positions du centre, du coin nw pour le nouveau zoom @@ -230,7 +780,7 @@ def retailleEtAffiche(self): def afficheImage(self): # Remplace l'image actuelle du canvas par l'image self.img, # positionnée dans le canvas suivant le calcul de "positionNouveauZoom" - try: self.canvas.delete(self.imgTk_id) #si jamais il n'y a pas encore d'image + try: self.canvas.delete(self.imgTk_id) # si jamais il n'y a pas encore d'image except: pass self.imgTk = ImageTk.PhotoImage(self.img) self.imgTk_id = self.canvas.create_image(0,0,image = self.imgTk,anchor="nw") @@ -241,11 +791,11 @@ def tracerMasqueBis(self): # appui sur un bouto self.frame.config(cursor="arrow") # on remet le cursor "normal" return self.listePointsJPG=list() # nouvelles données - self.polygone = False # pas de polygone fini + self.polygone = False # pas de polygone fini self.menagePol() self.fermerMasque() # efface le masque affiché en cours self.frame.config(cursor="plus") # curseur en mode ajout - self.boutonTracer.state(["pressed","!focus",'selected']) # etat séléctionné du bouton + self.boutonTracer.state(["pressed","!focus",'selected'])# etat séléctionné du bouton def retirerPointPolyligne(self): try: self.listePointsJPG.pop() @@ -274,18 +824,31 @@ def infoBulle(self,event,texte=" "): # affiche un i = ImageDraw.Draw(self.imageFichier) l,h = i.textsize(texte,font=None) try: self.bulle.destroy() - except: pass + except Exception as e: print(_("Erreur suppression d'info bulle : "),str(e)) self.bulle = tkinter.Toplevel() # nouvelle fenêtre pour l'info bulle self.bulle.overrideredirect(1) # sans le bordel tout autour self.bulle.geometry("%dx%d%+d%+d" % (l+10,h+6,event.x_root+15,event.y_root)) # position du coin nw de la fenêtre par rapport au curseur ttk.Label(self.bulle,text = texte,background="#ffffaa",relief = 'solid').pack() # texte, la taille de la fenêtre s'adapte au texte, style infobulle - #self.bulle.mainloop() # boucle d'attente d'événement sur la fenêtre (pas de pack possible) + #self.bulle.mainloop() # boucle d'attente d'événement sur la fenêtre (pas de pack possible) + def inverser(self): + self.inverse = not self.inverse + self.sauverMasque() + self.ouvrirMasque() + def sauverMasque(self): # création d'une image 200x200 avec un fond de couleur noire - img = Image.new("1",self.imageFichier.size) # 1 bit par pixel (noir et blanc (la couleur par défaut est le noir (http://pillow.readthedocs.org/en/latest/reference/Image.html) - dessin = ImageDraw.Draw(img) # création d'un objet Draw - dessin.polygon(self.listePointsJPG,fill="white",outline="green") - img.save(self.nomMasque,"TIFF") + if self.inverse: + img = Image.new("1",self.imageFichier.size,color=255) # 1 bit par pixel (noir et blanc (la couleur par défaut est le noir (http://pillow.readthedocs.org/en/latest/reference/Image.html) + dessin = ImageDraw.Draw(img) # création d'un objet Draw + dessin.draw + dessin.polygon(self.listePointsJPG,fill="black",outline="green") + img.save(self.nomMasque,"TIFF") + else: + img = Image.new("1",self.imageFichier.size,color=0) # 1 bit par pixel (noir et blanc (la couleur par défaut est le noir (http://pillow.readthedocs.org/en/latest/reference/Image.html) + dessin = ImageDraw.Draw(img) # création d'un objet Draw + dessin.draw + dessin.polygon(self.listePointsJPG,fill="white",outline="green") + img.save(self.nomMasque,"TIFF") def ouvrirMasque(self): @@ -323,8 +886,8 @@ def __init__(self,fenetre,image,points,dejaPlaces): self.file = image # nom de la photo avec chemin (au moins relatif) self.root = tkinter.Toplevel() - self.root.title( "Calibration GPS "+image) - self.root.title("Position des points sur la photo : "+image) # titre + self.root.title( _("Calibration GPS ")+image) + self.root.title(_("Position des points sur la photo : ")+image) # titre fenetreIcone(self.root) self.root.geometry( "900x900" ) self.dimMaxiCanvas = 600 # dimension max du canvas accueillant l'image @@ -341,8 +904,9 @@ def __init__(self,fenetre,image,points,dejaPlaces): self.retourSiAbandon = dejaPlaces self.boutonActif = ttk.Button() self.tempo = 0 + self.points = points # pour la suppression d'un point - # initialisations de l'affichage de l'image, dimesions du cadre, positionnement : + # initialisations de l'affichage de l'image, dimensions du cadre, positionnement : self.imageFichier = Image.open(self.file) self.largeurImageFichier, self.hauteurImageFichier = self.imageFichier.size if self.hauteurImageFichier>self.largeurImageFichier: # plus haut que large : on calcule l'échelle sur la hauteur @@ -370,22 +934,24 @@ def __init__(self,fenetre,image,points,dejaPlaces): # boutons de controle : self.frame3 = ttk.Frame(self.root,borderwidth = 2,relief = "sunken") - self.boutonQuitter = ttk.Button(self.frame3, text="Valider",command = self.quitter) - self.boutonSupprimerTousLesPoints = ttk.Button(self.frame3, text="Supprimer tous les points",command = self.supprimerTousLesPoints) - self.boutonAbandon = ttk.Button(self.frame3, text="Abandon",command = self.abandon) + self.boutonQuitter = ttk.Button(self.frame3, text=_("Valider"),command = self.quitter) + #self.boutonSupprimerTousLesPoints = ttk.Button(self.frame3, text=_("Supprimer tous les points"),command = self.supprimerTousLesPoints) + self.boutonSupprimerUnPoint = ttk.Button(self.frame3, text=_("Supprimer un ou plusieurs points"),command = self.supprimerUnPoint) + self.boutonAbandon = ttk.Button(self.frame3, text=_("Abandon"),command = self.abandon) self.boutonQuitter.pack(side='left',pady=2,ipady=2) - self.boutonSupprimerTousLesPoints.pack(side='left',pady=2,ipady=2,padx=5) + #self.boutonSupprimerTousLesPoints.pack(side='left',pady=2,ipady=2,padx=5) + self.boutonSupprimerUnPoint.pack(side='left',pady=2,ipady=2,padx=5) self.boutonAbandon.pack(side='left',pady=2,ipady=2,padx=5) self.frame3.pack(pady=10) self.frame4 = ttk.Frame(self.root,borderwidth = 2,relief = "sunken") - self.boutonchangerCouleurTexte = ttk.Button(self.frame4, text="Changer la couleur des libellés",command = self.changerCouleurTexte) + self.boutonchangerCouleurTexte = ttk.Button(self.frame4, text=_("Changer la couleur des libellés"),command = self.changerCouleurTexte) self.boutonchangerCouleurTexte.pack(pady=2,ipady=2,padx=5) self.frame4.pack(pady=10) # message d'inforamtion self.frame5 = ttk.Frame(self.root,borderwidth = 2) - ttk.Label(self.frame5,text="Utiliser la molette pour zoomer/dezoomer pendant la saisie.").pack() + ttk.Label(self.frame5,text=_("Utiliser la molette pour zoomer/dezoomer pendant la saisie.")).pack() self.frame5.pack() # évènements @@ -402,10 +968,18 @@ def __init__(self,fenetre,image,points,dejaPlaces): fenetre.wait_window(self.root) def placerBoutons(self,listePoints): # Place les boutons correspondants aux points de listePoints + textePoint = _("Placer le point ") # on raccourcit les textes si il y bcp de points (30 max)) + padding = 5 # version 2.41 + if listePoints.__len__()>5: + textePoint = _("Point ") + padding = 3 + if listePoints.__len__()>10: + textePoint = "" + padding = 1 for e in listePoints: # un bouton pour chaque référence de la liste des boutons; - b = ttk.Button(self.frame2, text="Placer le point "+e[0],cursor="plus",command = lambda i = (e[0],e[1]) :self.activerBouton(i)) + b = ttk.Button(self.frame2, text=textePoint+e[0],cursor="plus",width=0,command = lambda i = (e[0],e[1]) :self.activerBouton(i)) self.dicoBoutons.update({e[0]:b}) # mémo dans un dico du nom du point / références du bouton - b.pack(side="left",padx=5) + b.pack(side="left",padx=padding) def bouton1(self,event): # l'utilisateur appuie sur le bouton 1 de la souris @@ -452,7 +1026,7 @@ def moletteLinux5(self,event): # l'utilisateur Linu def redrawZoom(self, event): # l'utilisateur zoom avant avec la molette de la souris : mémo du zoom précédent if self.scale>self.maxScale: # si l'échelle passe à plusieurs pixels écran pour un pixel image on arrête - self.infoBulle(event,texte="Zoom maximum atteint") # l'utilisateur est informé + self.infoBulle(event,texte=_("Zoom maximum atteint")) # l'utilisateur est informé return self.listeSauveImages.append((self.xNW,self.yNW,self.xSE,self.ySE,self.img,self.scale)) # sauvegarde pour retour arrière (redrawDeZoom) self.positionNouveauZoom(event.x,event.y) # calcule les positions du centre, du coin nw pour le nouveau zoom @@ -509,7 +1083,7 @@ def afficheUnPoint(self,xJPG,yJPG,bouton): def activerBouton(self,boutonChoisi): # appui sur un bouton "ajouter un point" self.boutonActif.state(["!active","!focus","!pressed",'!selected']) # RAZ état de l'ancien bouton - if self.boutonActif==self.dicoBoutons[boutonChoisi[0]]: # réappuie sur le bouton actif : on le désactive et on quitte + if self.boutonActif==self.dicoBoutons[boutonChoisi[0]]: # réappuie sur le bouton actif : on le désactive et on quitte self.frame.config(cursor="arrow") self.boutonActif = ttk.Button() return # dans ce cas, c'est fini @@ -554,54 +1128,67 @@ def abandon(self): self.dicoPointsJPG = self.retourSiAbandon self.quitter() - def supprimerTousLesPoints(self): - aSupprimer = dict(self.dicoPointsJPG) - for cle in aSupprimer: + def supprimerTousLesPoints(self): # suppression de la localisation de tous les points GPS présents sur l'image self.file + aSupprimer = dict(self.dicoPointsJPG) # self.dicoPointsJPG[(self.boutonChoisi,self.file,self.numBoutonChoisi)] = (self.xJPG,self.yJPG) + for cle in aSupprimer: # if cle[1]==self.file: del self.dicoPointsJPG[cle] self.afficheImage() - + + def supprimerUnPoint(self): + tousLesPoints = dict(self.dicoPointsJPG) + aSupprimer = choisirDansUneListe(fenetre,[e for e,f,g in tousLesPoints if self.file==f],"Supprimer un ou plusieurs points").selectionFinale + for cle in tousLesPoints: + if cle[1]==self.file and cle[0] in aSupprimer: + del self.dicoPointsJPG[cle] + self.afficheImage() + ################# Classe Principale : la fenêtre maître de l'application, le menu, l'IHM class Interface(ttk.Frame): ################################## INITIALISATIONS - MENU - VALEURS PAR DEFAUT - EXIT ########################################################### - + + def __init__(self, fenetre, **kwargs): # initialise les "constantes" self.initialiseConstantes() - #affiche le logo durant 5 secondes - try: - global compteur - if compteur==1: - self.logo1 = ttk.Frame(fenetre) # cadre dans la fenetre ; affiche la photo sélectionnée - self.canvasLogo = tkinter.Canvas(self.logo1,width = 560, height = 200) # Canvas pour revevoir l'image - self.canvasLogo.pack(fill='both',expand = 1) - self.logo1.pack() - self.imageLogo = Image.open(self.logoCerema) - self.img = self.imageLogo.resize((560,200)) - self.imgTk = ImageTk.PhotoImage(self.img) - self.imgTk_id = self.canvasLogo.create_image(0,0,image = self.imgTk,anchor="nw") # affichage effectif de la photo dans canvasPhoto - fenetreIcone(fenetre) - for i in range(len(self.titreFenetre+" : Une interface graphique pour MicMac...")+8): - fenetre.title((self.titreFenetre+" : Une interface graphique pour MicMac...")[0:i]) - fenetre.update() - time.sleep(0.1) - self.logo1.destroy() - except Exception as e: - print(e) - # initialise les variables "chantier" self.initialiseValeursParDefaut() # valeurs par défaut pour un nouveau chantier (utile si pas encore de chantier) # pour les paramètres du chantier sous le répertoire chantier, aprés lancement Micmac - # On restaure la session précédente + # On restaure les paramètres et la session précédente self.restaureParamEnCours() # restaure les paramètres locaux par défaut + #affiche le logo durant 5 secondes, sauf demande expresse + if self.tacky: + try: + global compteur + if compteur==1: + self.canvasLogo1 = tkinter.Canvas(self.logo1,width = 560, height = 200) # Canvas pour revevoir l'image + self.canvasLogo1.pack(fill='both',expand = 1) + self.logo1.pack() + self.imageLogo = Image.open(self.logoCerema) + self.img = self.imageLogo.resize((560,200)) + self.imgTk = ImageTk.PhotoImage(self.img) + self.imgTk_id = self.canvasLogo1.create_image(0,0,image = self.imgTk,anchor="nw") # affichage effectif de la photo dans canvasPhoto + fenetreIcone(fenetre) + + try: + for i in range(len(self.titreFenetre+_(" : une interface graphique pour MicMac..."))+8): + fenetre.title((self.titreFenetre+_(" : une interface graphique pour MicMac..."))[0:i]) + fenetre.update() + time.sleep(0.1) + except: + print(_("Fermeture inatendue de la fenêtre.")) + + except Exception as e: + print(_("Erreur initialisation de la fenêtre principale : ")),str(e) + # Fenêtre principale : fenetre ttk.Frame.__init__(self, fenetre, **kwargs) @@ -611,7 +1198,7 @@ def __init__(self, fenetre, **kwargs): self.style.theme_use('clam') fenetreIcone(fenetre) fenetre.title(self.titreFenetre) # Nom de la fenêtre - fenetre.geometry("600x600+100+200") + fenetre.geometry("800x700+100+200") # fenentre.geometry("%dx%d%+d%+d" % (L,H,X,Y)) # construction des item du menu @@ -620,126 +1207,206 @@ def __init__(self, fenetre, **kwargs): # Fichier menuFichier = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable - menuFichier.add_command(label="Nouveau chantier", command=self.nouveauChantier) - menuFichier.add_command(label="Ouvrir un chantier", command=self.ouvreChantier) + menuFichier.add_command(label=_("Nouveau chantier"), command=self.nouveauChantier) + menuFichier.add_command(label=_("Ouvrir un chantier"), command=self.ouvreChantier) menuFichier.add_separator() - menuFichier.add_command(label="Enregistrer le chantier en cours", command=self.enregistreChantier) - menuFichier.add_command(label="Renommer le chantier en cours", command=self.renommeChantier) + menuFichier.add_command(label=_("Enregistrer le chantier en cours"), command=self.enregistreChantierAvecMessage) + menuFichier.add_command(label=_("Renommer ou déplacer le chantier en cours"), command=self.renommeChantier) menuFichier.add_separator() - menuFichier.add_command(label="Du ménage !", command=self.supprimeRepertoires) + menuFichier.add_command(label=_("Exporter le chantier en cours"), command=self.exporteChantier) + menuFichier.add_command(label=_("Importer un chantier"), command=self.importeChantier) menuFichier.add_separator() - menuFichier.add_command(label="Quitter", command=self.quitter) + menuFichier.add_command(label=_("Du ménage !"), command=self.supprimeRepertoires) + menuFichier.add_separator() + menuFichier.add_command(label=_("Quitter"), command=self.quitter) # Edition menuEdition = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable - menuEdition.add_command(label="Afficher l'état du chantier", command=self.afficheEtat) + menuEdition.add_command(label=_("Afficher l'état du chantier"), command=self.afficheEtat) menuEdition.add_separator() - menuEdition.add_command(label="Visualiser toutes les photos sélectionnées", command=self.afficherToutesLesPhotos) - menuEdition.add_command(label="Visualiser les points GPS", command=self.afficherLesPointsGPS) - menuEdition.add_command(label="Visualiser le masque 2D et l'image maitre", command=self.afficherMasqueEtMaitre) - menuEdition.add_command(label="Visualiser le masque 3D", command=self.afficheMasqueC3DC) - menuEdition.add_command(label="Visualiser la ligne horizontale/verticale", command=self.afficherLigneHV) - menuEdition.add_command(label="Visualiser la zone plane", command=self.afficherZonePlane) - menuEdition.add_command(label="Visualiser la distance", command=self.afficherDistance) + menuEdition.add_command(label=_("Visualiser toutes les photos sélectionnées"), command=self.afficherToutesLesPhotos) + menuEdition.add_command(label=_("Visualiser les points GPS"), command=self.afficherLesPointsGPS) + menuEdition.add_command(label=_("Visualiser les maîtresses et les masques"), command=self.afficherLesMaitresses) + menuEdition.add_command(label=_("Visualiser le masque sur mosaique Tarama"), command=self.afficherMasqueTarama) + menuEdition.add_command(label=_("Visualiser le masque 3D"), command=self.afficheMasqueC3DC) + menuEdition.add_command(label=_("Visualiser la ligne horizontale/verticale"), command=self.afficherLigneHV) + menuEdition.add_command(label=_("Visualiser la zone plane"), command=self.afficherZonePlane) + menuEdition.add_command(label=_("Visualiser la distance"), command=self.afficherDistance) + menuEdition.add_command(label=_("Visualiser les photos pour la calibration intrinsèque"), command=self.afficherCalibIntrinseque) + menuEdition.add_separator() + menuEdition.add_command(label=_("Afficher la trace complète du chantier"), command=self.lectureTraceMicMac) + menuEdition.add_command(label=_("Afficher la trace synthétique du chantier"), command=self.lectureTraceSynthetiqueMicMac) menuEdition.add_separator() - menuEdition.add_command(label="Afficher la trace complete du chantier", command=self.lectureTraceMicMac) - menuEdition.add_command(label="Afficher la trace synthétique du chantier", command=self.lectureTraceSynthetiqueMicMac) + menuEdition.add_command(label=_("Afficher la mosaïque Tarama"), command=self.afficheMosaiqueTarama) + menuEdition.add_command(label=_("Afficher l'ortho mosaïque Tawny"), command=self.afficheMosaiqueTawny) menuEdition.add_separator() - menuEdition.add_command(label="Afficher l'image 3D aprés Tapas", command=self.afficheApericloud) - menuEdition.add_command(label="Afficher l'image 3D aprés Malt ou C3DC", command=self.affiche3DNuage) + menuEdition.add_command(label=_("Afficher l'image 3D non densifiée"), command=self.afficheApericloud) + menuEdition.add_command(label=_("Afficher l'image 3D densifiée"), command=self.affiche3DNuage) + menuEdition.add_separator() + menuEdition.add_command(label=_("Lister-Visualiser les images 3D"), command=self.lister3DPly) + menuEdition.add_command(label=_("Fusionner des images 3D"), command=self.choisirPuisFusionnerPly) # menuMaintenance.add_command(label="Vérifier les dépendances",command=self.verifierDependances) # MicMac menuMicMac = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable - menuMicMac.add_command(label="Choisir des photos", command=self.lesPhotos) - menuMicMac.add_command(label="Options", command=self.optionsOnglet) + menuMicMac.add_command(label=_("Choisir des photos"), command=self.lesPhotos) + menuMicMac.add_command(label=_("Options"), command=self.optionsOnglet) menuMicMac.add_separator() - menuMicMac.add_command(label="Lancer MicMac", command=self.lanceMicMac) ## Ajout d'une option au menu fils menuFile + menuMicMac.add_command(label=_("Lancer MicMac"), command=self.lanceMicMac) ## Ajout d'une option au menu fils menuFile + + # GoPro + + menuGoPro = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable + menuGoPro.add_command(label=_("Options (GoPro par défaut)"), command=self.optionsGoPro) + menuGoPro.add_separator() + menuGoPro.add_command(label=_("Nouveau chantier : choisir une vidéo GoPro, ou autre"), command=self.laVideo) + menuGoPro.add_command(label=_("Sélection des meilleures images"), command=self.selectionGoPro) ## Sélection des "meilleures images" avec le taux passé en paramètre # Outils menuOutils = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable - menuOutils.add_command(label="Nom et focale de l'appareil photo", command=self.OutilAppareilPhoto) - menuOutils.add_command(label="Toutes les focales des photos", command=self.toutesLesFocales) - menuOutils.add_command(label="Mettre à jour DicoCamera.xml", command=self.miseAJourDicoCamera) - menuOutils.add_separator() - menuOutils.add_command(label="Qualité des photos 'line'", command=self.OutilQualitePhotosLine) - menuOutils.add_command(label="Qualité des photos 'All' ", command=self.OutilQualitePhotosAll) - - # Paramètrage - - menuParametres = tkinter.Menu(mainMenu,tearoff = 0) - menuParametres.add_command(label="Afficher les paramètres", command=self.afficheParam) ## Ajout d'une option au menu fils menuFile - menuParametres.add_separator() - menuParametres.add_command(label="Associer le répertoire bin de MicMac'", command=self.repMicmac) ## Ajout d'une option au menu fils menuFile - menuParametres.add_command(label="Associer 'exiftool'", command=self.repExiftool) ## Exiftool : sous MicMac\bin-aux si Windows, mais sinon ??? - menuParametres.add_command(label="Associer 'Meshlab' ou 'CloudCompare'", command=self.repMeslab) ## Meslab + menuOutils.add_command(label=_("Nom et focale de l'appareil photo"), command=self.OutilAppareilPhoto) + menuOutils.add_command(label=_("Toutes les focales des photos"), command=self.toutesLesFocales) + menuOutils.add_command(label=_("Mettre à jour DicoCamera.xml"), command=self.miseAJourDicoCamera) + menuOutils.add_separator() + menuOutils.add_command(label=_("Qualité des photos du dernier traitement"), command=self.nombrePointsHomologues) + menuOutils.add_command(label=_("Sélectionner les N meilleures photos"), command=self.OutilMeilleuresPhotos) + menuOutils.add_separator() + menuOutils.add_command(label=_("Qualité des photos 'line'"), command=self.OutilQualitePhotosLine) + menuOutils.add_command(label=_("Qualité des photos 'All' "), command=self.OutilQualitePhotosAll) + menuOutils.add_separator() + menuOutils.add_command(label=_("Modifier l'exif des photos"), command=self.majExif) + menuOutils.add_separator() + menuOutils.add_command(label=_("Modifier les options par défaut"), command=self.majOptionsParDefaut) + + # mode Expert + + menuExpert = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable + menuExpert.add_command(label=_("Exécuter lignes de commande"), command=self.lignesExpert) + menuExpert.add_command(label=_("Ajouter les points GPS d'un chantier"), command=self.ajoutPointsGPSAutreChantier) + + # Paramétrage + + def updateParam(): + if self.tacky: + menuParametres.entryconfig(10, label=_("Désactiver le 'tacky' message de lancement")) + else: + menuParametres.entryconfig(10, label=_("Activer le 'tacky' message de lancement")) + + menuParametres = tkinter.Menu(mainMenu,tearoff = 0,postcommand=updateParam) + menuParametres.add_command(label=_("Afficher les paramètres"), command=self.afficheParam) ## Ajout d'une option au menu fils menuFile + menuParametres.add_separator() + menuParametres.add_command(label=_("Associer le répertoire bin de MicMac"), command=self.repMicmac) ## Ajout d'une option au menu fils menuFile + menuParametres.add_command(label=_("Associer 'exiftool'"), command=self.repExiftool) ## Exiftool : sous MicMac\binaire-aux si Windows, mais sinon ??? + menuParametres.add_command(label=_("Associer 'convert' d'ImageMagick"), command=self.repConvert) ## convert : sous MicMac\binaire-aux si Windows, mais sinon ??? + menuParametres.add_command(label=_("Associer 'ffmpeg (décompacte les vidéos)"), command=self.repFfmpeg) ## ffmpeg : sous MicMac\binaire-aux si Windows, mais sinon ??? + menuParametres.add_command(label=_("Associer 'Meshlab' ou 'CloudCompare'"), command=self.repMeslab) ## Meslab + menuParametres.add_separator() + menuParametres.add_command(label=_("Changer la langue"), command = self.modifierLangue) + menuParametres.add_separator() + menuParametres.add_command(label=_("Désactive/Active le tacky message de lancement..."),command=self.modifierTacky) ## Meslab + + # Indices surfaciques + + menuIndices = tkinter.Menu(mainMenu,tearoff = 0) + menuIndices.add_command(label=_("Affichage de la surface interpolée"), command=self.afficheSurf) + menuIndices.add_command(label=_("Calcul des indices"), command=self.calculIndices) + menuIndices.add_command(label=_("Calcul de la PMP"), command=self.calculPmp) # Aide menuAide = tkinter.Menu(mainMenu,tearoff = 0) ## menu fils : menuFichier, par défaut tearOff = 1, détachable - menuAide.add_command(label="Pour commencer...", command=self.commencer) - menuAide.add_command(label="Aide", command=self.aide) - menuAide.add_command(label="Quelques conseils", command=self.conseils) - menuAide.add_command(label="A Propos", command=self.aPropos) + menuAide.add_command(label=_("Pour commencer..."), command=self.commencer) + menuAide.add_command(label=_("Aide"), command=self.aide) + menuAide.add_command(label=_("Quelques conseils"), command=self.conseils) + menuAide.add_command(label=_("Historique"), command=self.historiqueDesVersions) + menuAide.add_command(label=_("A Propos"), command=self.aPropos) # ajout des items dans le menu principal : - mainMenu.add_cascade(label = "Fichier",menu=menuFichier) - mainMenu.add_cascade(label = "Edition",menu=menuEdition) + mainMenu.add_cascade(label = _("Fichier"),menu=menuFichier) + mainMenu.add_cascade(label = _("Edition"),menu=menuEdition) mainMenu.add_cascade(label = "MicMac",menu=menuMicMac) - mainMenu.add_cascade(label = "Outils",menu=menuOutils) - mainMenu.add_cascade(label = "Paramètrage",menu=menuParametres) - mainMenu.add_cascade(label = "Aide",menu=menuAide) + mainMenu.add_cascade(label = _("Vidéo"),menu=menuGoPro) + mainMenu.add_cascade(label = _("Outils"),menu=menuOutils) + mainMenu.add_cascade(label = _("Expert"),menu=menuExpert) + mainMenu.add_cascade(label = _("Paramétrage"),menu=menuParametres) + '''mainMenu.add_cascade(label = _("Indices_surfaciques"),menu=menuIndices)''' #Non fonctionnel pour le moment + mainMenu.add_cascade(label = _("Aide"),menu=menuAide) # affichage du menu principal dans la fenêtre fenetre.config(menu = mainMenu) - + # Fonction a éxécuter lors de la sortie du programme fenetre.protocol("WM_DELETE_WINDOW", self.quitter) # zone de test éventuel : - - - ####################### initialiseValeursParDefaut du défaut : On choisit de nouvelles photos : on oublie ce qui précéde, sauf les paramètres généraux de aperodedenis (param micmac) - + + #initialise les valeurs par défaut au lancement de l'outil + def initialiseConstantes(self): - # initialisation variables globales et propre au contexte local : + # Pour suivre les nouvelles versions - self.repertoireScript = os.path.dirname(sys.argv[0]) # là sont enrgistrés les paramètres généraux et le dossie ren cours + self.versionInternetAncienne = str() # Dernière version lue sur GitHub + self.messageVersion = bool(True) # l'utilisateur peut désactiver l'affichage du message d'avertissement + + # initialisation variables globales et propre au contexte local : + + self.repertoireScript = repertoire_script # là où est le script et les logos cerema et IGN + self.repertoireData = repertoire_data # là ou l'on peut écrire des données self.systeme = os.name # nt ou posix - self.version = " V 1.4" self.nomApplication = os.path.splitext(os.path.basename(sys.argv[0]))[0] # Nom du script - self.titreFenetre = self.nomApplication+self.version # nom du programme titre de la fenêtre + self.titreFenetre = self.nomApplication+version # nom du programme titre de la fenêtre (version = varaioble globale) self.tousLesChantiers = list() # liste de tous les réchantiers créés + self.exptxt = "0" # 0 pour exptxt format binaire, 1 format texte (pts homologues) + self.indiceTravail = 0 # lors de l'installation, valeur initial de l'indice des répertoires de travail # Les 3 chemins utiles : mecmac\bin, meshlab et exiftool : - - self.micMac = 'Pas de répertoire désigné pour MicMac\\bin' # oar défaut il n'y a pas de répertoire micMac, sauf si restauration ligne suivante - self.meshlab = 'Pas de fichier désigné pour ouvrir les .PLY' - self.exiftool = "Pas de chemin pour ExifTool" - self.mm3d = "Pas de fichier pour mm3d" - + self.micMac = _('Pas de répertoire désigné pour MicMac\\bin') # oar défaut il n'y a pas de répertoire micMac, sauf si restauration ligne suivante + self.meshlab = _('Pas de fichier désigné pour ouvrir les .PLY') + self.exiftool = _("Pas de chemin pour ExifTool") + self.mm3d = _("Pas de fichier pour mm3d") # lanceur des commandes micmac + self.ffmpeg = _("Pas de fichier pour ffmpeg") # outil d'extraction des images à partir de video + self.mercurialMicMac = _("Pas de version MicMac") + self.mercurialMicMacChantier = "" + self.convertMagick = _("Pas de version Image Magick") # pour convertir les formats + self.noRep = [self.micMac, self.meshlab, self.exiftool, self.mm3d, self.convertMagick,self.ffmpeg] # pour des question de traduction si message et pas si répertoire !! + + # le controle des photos + + self.dimensionsDesPhotos = list() # [(x,Image.open(x).size) for x in self.photosSansChemin] + self.dimensionsOK = bool() # set([y for (x,y) in self.dimensionsDesPhotos]).__len__()==1 # vrai si une seule taille + self.exifsDesPhotos = list() # [(x,self.tagExif("FocalLength",x)) for x in self.photosSansChemin] + self.exifsOK = bool() # set([y for (x,y) in self.exifsDesPhotos]).__len__()==1 # vrai si une seule focale + self.assezDePhotos = bool() # il faut au moins 2 photos pour traiter + + # les caractéristiques de l'appareil photo : + + self.fabricant = str() + self.nomCamera = str() + self.focale = str() + self.focale35MM = str() + # Les noms des fichiers xml self.masque3DSansChemin = "AperiCloud_selectionInfo.xml" # nom du fichier XML du masque 3D, fabriqué par self.masque3DBisSansChemin = "AperiCloud_polyg3d.xml" # nom du second fichier XML pour le masque 3D self.dicoAppuis = "Dico-Appuis.xml" # nom du fichier XML des points d'appui (nom, X,Y,Z,incertitude) pour Bascule - self.mesureAppuis = "Mesure-Appuis.xml" # nom du XML positionnant les points d'appuis dans les photos + self.mesureAppuis = "Mesure-Appuis.xml" # nom du XML positionnant les points d'appuis GPS dans les photos self.miseAEchelle = "MiseAEchelle.xml" # pour l'axe des x, le plan self.dicoCameraUserRelatif = "include/XML User/DicoCamera.xml" # relatif au répertoire MicMac self.dicoCameraGlobalRelatif = "include/XML_MicMac/DicoCamera.xml" # relatif au répertoire MicMac # Constante sous nt et posix : - self.nomTapioca = "Tapioca" + self.nomTapioca = "Tapioca" self.nomTapas = "Tapas" self.nomMalt = "Malt" self.nomApericloud = "AperiCloud" @@ -769,13 +1436,22 @@ def initialiseConstantes(self): self.resul100=ttk.Frame(fenetre,height=50,relief='sunken') self.texte101=ttk.Label(self.resul100, text="",justify='center',style="C.TButton") self.texte101.pack(ipadx=5,ipady=5) + + # la fenetre pour afficher les textes (traces et aides) + + self.resul200 = ttk.Frame(fenetre,height=100,relief='sunken') # fenêtre texte pour afficher le bilan + self.scrollbar = ttk.Scrollbar(self.resul200) + self.scrollbar.pack(side='right',fill='y',expand=1) + self.scrollbar.config(command=self.yviewTexte) + self.texte201 = tkinter.Text(self.resul200,width=200,height=100,yscrollcommand = self.scrollbar.set,wrap='word') + self.texte201.pack() # Les variables, Widgets et options de la boite à onglet : # Pour tapioca - self.echelle1 = tkinter.StringVar() # nécessaire pour définir la variable obtenue le widget - self.echelle2 = tkinter.StringVar() + self.echelle1 = tkinter.StringVar() # nécessaire pour définir la variable obtenue le widget + self.echelle2 = tkinter.StringVar() self.echelle3 = tkinter.StringVar() self.echelle4 = tkinter.StringVar() self.delta = tkinter.StringVar() @@ -783,18 +1459,31 @@ def initialiseConstantes(self): self.modeTapioca = tkinter.StringVar() self.modeMalt = tkinter.StringVar() - # Pour tapas : - self.modeCheckedTapas = tkinter.StringVar() # nécessaire pour définir la variable obtenue par radiobutton - self.arretApresTapas = tkinter.IntVar() + # Pour tapas : - #pour la calibration + self.modeCheckedTapas = tkinter.StringVar() # nécessaire pour définir la variable obtenue par radiobutton + self.arretApresTapas = tkinter.IntVar() # + self.lancerTarama = tkinter.IntVar() # booléen : Tarama crée une mosaique des images, utilisable pour faire un masque sur Malt/ortho + self.calibSeule = tkinter.BooleanVar() + self.repCalibSeule = "PhotosCalibrationIntrinseque" # nom du répertoire pour cantonner les photos servant uniquement à la calibration + + # pour la calibration self.distance = tkinter.StringVar() - # L'onglet : + # Pour Malt - self.modeMalt = tkinter.StringVar() + self.zoomF = tkinter.StringVar() # niveau de zoom final pour malt : 8,4,2,1 1 le plus dense + self.photosUtilesAutourDuMaitre = tkinter.IntVar() # pour le mode geomimage seul : nombre de photos avant/aprés autour de la maitresse + self.tawny = tkinter.BooleanVar() # pour le mode Orthophoto seul : lancer ou non tawny + self.tawnyParam = tkinter.StringVar() # paramètres manuel de tawny + + # pour C3DC + + self.modeC3DC = tkinter.StringVar() + + # L'onglet : self.onglets = ttk.Notebook(fenetre) # create Notebook in "master" : boite à onglet, supprimé par menageEcran() comme les frames @@ -812,32 +1501,32 @@ def initialiseConstantes(self): self.item404.pack(anchor='w') self.item404.state(['disabled']) # dans cette version de l'outil - # tapioca Echelle 1 + # tapioca Echelle 1 All self.item480 = ttk.Frame(self.item400,height=50,relief='sunken',padding="0.3cm") - self.item481 = ttk.Label(self.item480, text="Echelle image (-1 pour l'image entière) :") + self.item481 = ttk.Label(self.item480, text=_("Echelle image (-1 pour l'image entière) :")) self.item482 = ttk.Entry(self.item480,textvariable=self.echelle1) self.item481.pack() self.item482.pack() - # tapioca Echelle2 (MultiScale) + # tapioca Echelle2 et 3 (MultiScale) self.item460=ttk.Frame(self.item400,height=50,relief='sunken',padding="0.3cm") - self.item461=ttk.Label(self.item460, text="Echelle image réduite : ") + self.item461=ttk.Label(self.item460, text=_("Echelle image réduite : ")) self.item462=ttk.Entry(self.item460,textvariable=self.echelle2) self.item461.pack() self.item462.pack() - self.item463=ttk.Label(self.item460, text="Seconde Echelle (-1 pour l'image entière) :") + self.item463=ttk.Label(self.item460, text=_("Seconde Echelle (-1 pour l'image entière) :")) self.item464=ttk.Entry(self.item460,textvariable=self.echelle3) self.item463.pack() self.item464.pack() - # tapioca Delta + # tapioca Delta Echelle4 self.item470=ttk.Frame(self.item400,height=50,relief='sunken',padding="0.3cm") - self.item471=ttk.Label(self.item470, text="Echelle image (-1 pour l'image entière) :") + self.item471=ttk.Label(self.item470, text=_("Echelle image (-1 pour l'image entière) :")) self.item472=ttk.Entry(self.item470,textvariable=self.echelle4) - self.item473=ttk.Label(self.item470, text="Delta (nombre d'images se recouvrant, avant et après) : ") + self.item473=ttk.Label(self.item470, text=_("Delta (nombre d'images se recouvrant, avant et après) : ")) self.item474=ttk.Entry(self.item470,textvariable=self.delta) self.item471.pack() self.item472.pack() @@ -848,19 +1537,38 @@ def initialiseConstantes(self): # Tapas : 500 self.item500=ttk.Frame(self.onglets,height=150,relief='sunken',padding="0.3cm") - modesTapas=[('RadialExtended','RadialExtended','active'),('RadialStd','RadialStd','active'),('RadialBasic','RadialBasic','active'), - ('Fraser','Fraser','disabled'),('FraserBasic','FraserBasic','disabled'),('FishEyeEqui','FishEyeEqui','disabled'), - ('HemiEqui','HemiEqui','disabled'),('AutoCal','AutoCal','disabled'),('Figee','Figee','disabled')] # déconnexion texte affichée, valeur retournée + modesTapas=[('RadialExtended (REFLEX)','RadialExtended','active'), + ('RadialStd (Compact)','RadialStd','active'), + ('RadialBasic (SmartPhone)','RadialBasic','active'), + ('FishEyeBasic (GOPRO)','FishEyeBasic','active'), + ('FishEyeEqui','FishEyeEqui','active')] # déconnexion texte affichée, valeur retournée +## ('Fraser','Fraser','disabled'), +## ('FraserBasic','FraserBasic','disabled'), +## ('HemiEqui','HemiEqui','disabled'), +## ('AutoCal','AutoCal','disabled'), +## ('Figee','Figee','disabled') for t,m,s in modesTapas: b=ttk.Radiobutton(self.item500, text=t, variable=self.modeCheckedTapas, value=m) b.pack(anchor='w') b.state([s]) - self.modeCheckedTapas.set('RadialExtended') # valeur par défaut nécessaire pour définir la variable obtenue par radiobutton - self.item510 = ttk.Frame(self.item500,height=50,relief='sunken',padding="0.3cm") # pour le check button, fera un encadrement - self.item511 = ttk.Checkbutton(self.item510, variable=self.arretApresTapas, text="Arrêter le traitement après TAPAS") - self.item511.pack() - self.item510.pack() + self.item520 = ttk.Frame(self.item500,height=50,relief='sunken',padding="0.3cm") # pour la calibration, fera un encadrement + # photosPourCalibrationIntrinseque + self.item525 = ttk.Button(self.item520,text=_("Choisir quelques photos pour la calibration intrinsèques"),command=self.imagesCalibrationIntrinseques) + self.item526 = ttk.Label(self.item520, text="") + self.item527 = ttk.Checkbutton(self.item520, variable=self.calibSeule, + text=_(" N'utiliser ces photos que pour la calibration") + "\n" + _("(exemple : focales différentes)")) # inutile ? + self.item528 = ttk.Label(self.item520, text=_("Toutes ces photos doivent avoir la même focale,") + "\n" + _("éventuellement différente de la focale des autres photos.")) + self.item510 = ttk.Frame(self.item500,height=50,relief='sunken',padding="0.3cm") # pour le check button, fera un encadrement + self.item530 = ttk.Checkbutton(self.item510, variable=self.lancerTarama, text=_("lancer Tarama après TAPAS : mosaique pouvant définir un masque pour Malt/ortho)")) + self.item530.pack(ipady=5) + self.item540 = ttk.Frame(self.item500,height=50,relief='sunken',padding="0.3cm") # pour le check button, fera un encadrement + self.item550 = ttk.Checkbutton(self.item540, variable=self.arretApresTapas, text=_("Arrêter le traitement après TAPAS")) + self.item550.pack(ipady=5) + self.item525.pack() + self.item526.pack() + #self.item527.pack() # je ne comprends plus l'intérêt de cet item : la suite s'accomode très bien de 2 focales différentes... + self.item528.pack() # Calibration : 950 @@ -876,17 +1584,17 @@ def initialiseConstantes(self): padding="0.3cm") self.item961 = ttk.Label(self.item960, - text='Choisir entre :') + text=_('Choisir entre :')) self.item962 = ttk.Button(self.item960, - text='Ligne horizontale', + text=_('Ligne horizontale'), command= self.ligneHorizontale) self.item963 = ttk.Label(self.item960, - text='ou') + text=_('ou')) self.item964 = ttk.Button(self.item960, - text='Ligne verticale', + text=_('Ligne verticale'), command= self.ligneVerticale) self.item961.pack(ipadx=5,padx=5,ipady=2) @@ -899,7 +1607,7 @@ def initialiseConstantes(self): # conjonction de coordination : self.item965 = ttk.Frame( self.item950) - self.item966 = ttk.Label(self.item965,text='ET :') + self.item966 = ttk.Label(self.item965,text=_('ET :')) self.item966.pack() self.item965.pack() @@ -911,17 +1619,17 @@ def initialiseConstantes(self): padding="0.3cm") self.item971 = ttk.Label(self.item970, - text='Choisir entre :') + text=_('Choisir entre :')) self.item972 = ttk.Button(self.item970, - text='Zone plane horizontale', + text=_('Zone plane horizontale'), command= self.planHorizontal) self.item973 = ttk.Label(self.item970, - text='ou') + text=_('ou')) self.item974 = ttk.Button(self.item970, - text='Zone plane verticale', + text=_('Zone plane verticale'), command= self.planVertical) self.item971.pack(ipadx=5,padx=5,ipady=2) @@ -933,7 +1641,7 @@ def initialiseConstantes(self): # conjonction de coordination : self.item975 = ttk.Frame(self.item950) - self.item976 = ttk.Label(self.item975,text='ET :') + self.item976 = ttk.Label(self.item975,text=_('ET :')) self.item976.pack() self.item975.pack() @@ -944,12 +1652,12 @@ def initialiseConstantes(self): relief='sunken', padding="0.3cm") self.item981 = ttk.Label(self.item980, - text='Distance entre les 2 points :') + text=_('Distance entre les 2 points :')) self.item982 = ttk.Entry(self.item980,textvariable=self.distance) # distance self.item983 = ttk.Button(self.item980, - text='Placer 2 points identiques sur 2 photos', + text=_('Placer 2 points identiques sur 2 photos'), command= self.placer2Points) self.item981.pack() @@ -959,55 +1667,131 @@ def initialiseConstantes(self): self.item990 = ttk.Frame( self.item950, relief='sunken') - self.item991 = ttk.Label(self.item990,text='\nPour annuler la calibration mettre la distance = 0') + self.item991 = ttk.Label(self.item990,text='\n' + _('Pour annuler la calibration mettre la distance = 0')) self.item991.pack() - # Malt + # Onglet Malt : item700 + + self.item700 = ttk.Frame(self.onglets,height=5,relief='sunken',padding="0.3cm") + + self.modesMalt = [(_('UrbanMNE pour photos urbaines'),'UrbanMNE'), + (_("GeomImage pour photos du sol ou d'objets"),'GeomImage'), + (_('Ortho pour orthophotos de terrain naturel [f(x,y)=z)]'),'Ortho'), + (_('AperoDeDenis choisit pour vous les options de GeomImage'),'AperoDeDenis') + ] + + self.TawnyListeparam = ( + "* [Name=DEq] INT :: {Degree of equalization (Def=1)}\n"+ + "* [Name=DEqXY] Pt2di :: {Degree of equalization, if diff in X and Y}\n"+ + "* more : see MicMac documentation" + ) - self.item700 = ttk.Frame(self.onglets,height=5,relief='sunken',padding="0.3cm") - - self.modesMalt=[('Ortho pour orthophotos','Ortho'),('UrbanMNE pour photos urbaine','UrbanMNE'),('GeomImage pour photos du sol','GeomImage')] for t,m in self.modesMalt: - b=ttk.Radiobutton(self.item700, text=t, variable=self.modeMalt, value=m) + b = ttk.Radiobutton(self.item700, text=t, variable=self.modeMalt, value=m, command=self.optionsMalt) b.pack(anchor='w') if self.modesMalt==m: b.state(['selected']) self.modeMalt.set(m) # positionne la valeur initiale sélectionnée - - self.item710=ttk.Frame(self.item700,height=50,relief='sunken',padding="0.2cm") # pour le check button, fera un encadrement - self.item701=ttk.Label(self.item710,text="image maitresse = ") - self.item702=ttk.Button(self.item710,text="Choisir l'image maîtresse",command=self.imageMaitresse) - self.item703=ttk.Label(self.item710,text="masque = ") - self.item704=ttk.Button(self.item710,text='Tracer le masque',command=self.traceMasque) - self.item705=ttk.Label(self.item700,text="Attention : le masque 3D de C3DC a la priorité sur Malt") - self.item701.pack() - self.item702.pack(ipady=2,pady=10) + + # Boites item710 et 730 dans item700 pour l'option GeomImage + + self.item710 = ttk.Frame(self.item700,height=50,relief='sunken',padding="0.2cm") # pour le check button, fera un encadrement + self.item701 = ttk.Label(self.item710) # nom ou nombre d'images maitresses + self.item702 = ttk.Button(self.item710,text=_("Choisir les maîtresses"),command=self.imageMaitresse) + self.item703 = ttk.Label(self.item710) # nom ou nombre de masques + self.item704 = ttk.Button(self.item710,text=_('Tracer les masques'),command=self.tracerLesMasques) + self.item705 = ttk.Label(self.item710,text=_("Attention : Le masque 3D de C3DC a la priorité sur Malt") + "\n" + _("Pour supprimer un masque : supprimer la maitresse")) + self.item730 = ttk.Frame(self.item700,relief='sunken',padding="0.2cm") # fera un encadrement pour nb photos à retenir + self.item732 = ttk.Label(self.item730,text=_("Nombre de photos à retenir autour de l'image maitresse (-1 = toutes) :")) + self.item733 = ttk.Entry(self.item730,width=5,textvariable=self.photosUtilesAutourDuMaitre) + + + # Boite item720 pour le niveau de zoom final + + self.item720 = ttk.Frame(self.item700,relief='sunken',padding="0.2cm") # fera un encadrement pour le zoom + self.item722 = ttk.Label(self.item720,text=_("Zoom final : 8, 4, 2 ou 1 (8=le plus rapide, 1=le plus précis)")) + self.item723 = ttk.Entry(self.item720,width=5,textvariable=self.zoomF) + + + # Boite item740 pour Tawny dans item700 pour l'option Ortho + + self.item740 = ttk.Frame(self.item700,relief='sunken',padding="0.2cm") # fera un encadrement + self.item741 = ttk.Checkbutton(self.item740, variable=self.tawny, text=_("Lancer tawny après MALT")) + self.item742 = ttk.Label(self.item740,text=_("Tawny génère une ortho mosaïque qui sera drapée sur le nuage densifié.")+"\n"+ + _("Saisir si besoin les paramètres facultatifs, exemple :") + + "\nDEq=2 DegRapXY=[4,1]") + self.item743 = ttk.Entry(self.item740,width=45,textvariable=self.tawnyParam) + self.item744 = ttk.Label(self.item740,text=_("Liste des paramètres facultatifs nommés :") + "\n"+self.TawnyListeparam) + + # Bouton pour tracer un masque sur la mosaique créée par tarama + + self.item745 = ttk.Button(self.item700,text=_('Tracer un masque sur la mosaïque Tarama'),command=self.tracerUnMasqueSurMosaiqueTarama) + + + # Boite item750 dans item700 pour l'option AperoDeDenis + + self.item750 = ttk.Frame(self.item700,height=50,relief='sunken',padding="0.2cm") # pour le check button, fera un encadrement + self.item751 = ttk.Label(self.item750,text=_("La saisie des masques n'est active qu'aprés Tapas.")) # nom ou nombre d'images maitresses + self.item752 = ttk.Label(self.item750,text=_("Pas de masque.")) # nom ou nombre de masque + self.item753 = ttk.Button(self.item750,text=_('Tracer les masques'),command=self.tracerLesMasquesApero) + self.item754 = ttk.Label(self.item750,text=_("Attention : Le masque 3D de C3DC a la priorité sur Malt") + "\n" + + _("Pour supprimer un masque : supprimer la maitresse dans l'option GeomImage")+"\n" + + _("Remarque : les masques sont communs à GeomImage et AperoDeDenis")+"\n" + + _("Consulter la documentation.")) + + + self.item701.pack() + self.item702.pack() self.item703.pack() self.item704.pack(ipady=2,pady=10) self.item705.pack() - self.item710.pack(pady=15) - - - # C3DC + self.item722.pack(side='left') + self.item723.pack(side='left') + self.item720.pack(pady=10) + self.item732.pack(side='left') + self.item733.pack(side='left') + self.item741.pack() + self.item742.pack() + self.item743.pack() + self.item744.pack() + self.item751.pack() + self.item752.pack() + self.item753.pack(ipady=2,pady=10) + self.item754.pack() + + + # Boite item800 pour l'onglet C3DC self.item800 = ttk.Frame(self.onglets,height=5,relief='sunken',padding="0.3cm") + + #self.item810 = ttk.Radiobutton(self.item800, text="Ground", variable=self.modeC3DC, value='Ground') non supportée + self.item811 = ttk.Radiobutton(self.item800, text=_("Statue - avec drapage"), variable=self.modeC3DC, value='Statue') + self.item812 = ttk.Radiobutton(self.item800, text=_("QuickMac - rapide, sans drapage"), variable=self.modeC3DC, value='QuickMac') + #self.item810.pack(anchor='w') + self.item811.pack(anchor='w') + self.item812.pack(anchor='w') + #self.item810.state(['disabled']) # dans micmac : non supporté - self.item801 = ttk.Button(self.item800,text='Tracer le masque 3D sur le nuage AperiCloud',command=self.affiche3DApericloud) + self.item801 = ttk.Button(self.item800,text=_('Tracer le masque 3D sur le nuage AperiCloud'),command=self.affiche3DApericloud) self.item801.pack(ipady=2,pady=10) - self.item802 = ttk.Label(self.item800, text= "Tapas doit avoir créé un nuage de points.\n\n"+\ - "Dans l'outil : \n"+\ - "Définir le masque : F9 \n"+\ - "Ajouter un point : clic gauche\n"+\ - "Fermer le polygone : clic droit\n"+\ - "Sélectionner : touche espace\n"+\ - "Sauver le masque : Ctrl S.\n"+ - "Quitter : Ctrl Q.\n\n"+ - "Supprimer le masque : Ctrl Q (sans saisie préalable).\n\n"+ - "Attention : C3DC a la priorité sur le masque 2D de Malt") - self.item802.pack(ipady=2,pady=10) - - - #Ajout des onglets dans la boite à onglet : + self.item802 = ttk.Button(self.item800,text=_('Supprimer le masque 3D'),command=self.supprimeMasque3D) + self.item802.pack(ipady=2,pady=10) + self.item803 = ttk.Label(self.item800, text= \ + _("Dans l'outil : " ) +"\n"+\ + _("Définir le masque : F9 ") + "\n"+\ + _("Ajouter un point : clic gauche") + "\n"+\ + _("Fermer le polygone : clic droit") + "\n"+\ + _("Sélectionner : touche espace") +"\n"+\ + _("Sauver le masque : Ctrl S.") + "\n"+ + _("Quitter : Ctrl Q.") + "\n\n"+ + _("Agrandir les points : Maj +") + "\n\n"+\ + _("Saisie simultanée de plusieurs masques disjoints possible") + "\n\n"+\ + _("C3DC a la priorité sur le masque 2D de Malt")) + self.item803.pack(ipady=2,pady=10) + self.item804 = ttk.Label(self.item800, text= "") + self.item804.pack(ipady=2,pady=10) + + # Ajout des onglets dans la boite à onglet : self.onglets.add(self.item400,text="Tapioca") # add onglet to Notebook self.onglets.add(self.item500,text="Tapas") # add onglet to Notebook @@ -1020,10 +1804,10 @@ def initialiseConstantes(self): self.item450 = ttk.Frame(fenetre) # frame pour bouton de validation, permet un ménage facile self.item451 = ttk.Button(self.item450, - text=' Valider les options', + text=_(' Valider les options'), command=self.finOptionsOK) # bouton permettant de tout valider self.item452 = ttk.Button(self.item450, - text=' Annuler', + text=_(' Annuler'), command=self.finOptionsKO) # bouton permettant de tout annuler # les 2 boutons globaux : @@ -1032,32 +1816,247 @@ def initialiseConstantes(self): self.item452.pack(side='left') # La boite de dialogue pour demander les dimensions du capteur de l'appareil photo - + self.item1000 = ttk.Frame(fenetre) self.item1001 = ttk.Label(self.item1000) self.item1002 = ttk.Label(self.item1000, - text= "Indiquer les dimensions du capteur, en mm.\n"+\ - "par exemple :\n\n 5.7 7.6 \n\n"+\ - "Le site :\n \http://www.dpreview.com/products\n"+\ - "fournit les dimensions de tous les appareils photos.") + text= _("Indiquer les dimensions du capteur, en mm.") + "\n"+\ + _("par exemple :") + "\n\n 5.7 7.6 \n\n"+\ + _("Le site :") + "\n \http://www.dpreview.com/products\n"+\ + _("fournit les dimensions de tous les appareils photos.")) self.item1003 = ttk.Entry(self.item1000) self.item1004 = ttk.Button(self.item1000, - text=' Valider', + text=_(' Valider'), command=self.dimensionCapteurOK) # bouton permettant de tout valider self.item1005 = ttk.Button(self.item1000, - text=' Annuler', + text=_(' Annuler'), command=self.dimensionCapteurKO) # bouton permettant de tout annuler self.item1001.pack(pady=15) self.item1002.pack(pady=15) self.item1003.pack(pady=15) self.item1004.pack(pady=15) self.item1005.pack(pady=15) + + + # La boite de dialogue pour demander les options pour la video (GoPro par défaut) + + self.goProMaker = tkinter.StringVar() + self.goProFocale35 = tkinter.StringVar() + self.goProFocale = tkinter.StringVar() + self.goProNomCamera = tkinter.StringVar() + self.goProNbParSec = tkinter.StringVar() # taux de conservation des photos pour DIV + self.goProEchelle = tkinter.StringVar() # pour tapioca + self.goProDelta = tkinter.StringVar() + + # GoPRO : les options à saisir pour le traitement GoPro : valeurs par défaut (non modifiées lors de la création d'un nouveau chantier) + + self.goProMaker.set("GoPro") + self.goProFocale35.set("16.53") # Hero3 + self.goProFocale.set("2.98") #2.98 4.52 + self.goProNomCamera.set("GoPro Hero3 HD3") + self.goProNbParSec.set("3") # taux de conservation des photos pour DIV + self.goProEchelle.set("1000") # pour tapioca + self.goProDelta.set("10") + self.extensionChoisie = ".JPG" + + + self.item2000 = ttk.Frame(fenetre) + self.item2010 = ttk.Label(self.item2000, + text=_("Marque de l'appareil : ")) + self.item2011 = ttk.Entry(self.item2000, + textvariable=self.goProMaker) + self.item2001 = ttk.Label(self.item2000, + text=_("Nom de la camera : ")) + self.item2002 = ttk.Entry(self.item2000, + textvariable=self.goProNomCamera) + self.item2003 = ttk.Label(self.item2000, + text= _("Focale en mm:")) + self.item2004 = ttk.Entry(self.item2000, + textvariable=self.goProFocale) + self.item2005 = ttk.Label(self.item2000, + text= _("Focale équivalente 35mm :")) + self.item2006 = ttk.Entry(self.item2000, + textvariable=self.goProFocale35) + self.item2007 = ttk.Label(self.item2000, + text= "--------------\n" + _("Nombre d'images à conserver par seconde :"), + justify='center') + self.item2008 = ttk.Entry(self.item2000, + textvariable=self.goProNbParSec) + + self.item2020 = ttk.Button(self.item2000, + text=_(' Valider'), + command=self.optionsGoProOK) # bouton permettant de tout valider + self.item2021 = ttk.Button(self.item2000, + text=_(' Annuler'), + command=self.optionsGoProKO) # bouton permettant de tout annuler + self.item2010.pack(pady=5) + self.item2011.pack(pady=1) + self.item2001.pack(pady=5) + self.item2002.pack(pady=1) + self.item2003.pack(pady=5) + self.item2004.pack(pady=1) + self.item2005.pack(pady=5) + self.item2006.pack(pady=1) + self.item2007.pack(pady=5) + self.item2008.pack(pady=1) + self.item2020.pack(pady=5) + self.item2021.pack(pady=5) + + self.goProMaker.set("GoPro") + self.goProFocale35.set("16.53") # Hero3 + self.goProFocale.set("2.98") #2.98 4.52 + self.goProNomCamera.set("GoPro Hero3 HD3") + self.goProNbParSec.set("3") # taux de conservation des photos pour DIV + self.goProEchelle.set("1000") # pour tapioca + self.goProDelta.set("10") + + # la fenêtre des options pour les indices de surfaces: + + self.methode_interpol = tkinter.StringVar() + self.pas_maillage = tkinter.StringVar() + + self.methode_interpol.set("") + self.pas_maillage.set("") + + self.item7000 = ttk.Frame(fenetre) + + self.modes_interpol = [(_('linéaire'),'linear'), + (_("cubique"),'cubic')] + + self.item7010 = ttk.Label(self.item7000, + text=_(" Choisir la méthode d'interpolation ")) + self.item7020 = ttk.Label(self.item7000, + text=_(" Choisir le pas du maillage ")) + self.item7021 = ttk.Entry(self.item7000, + textvariable=self.pas_maillage) + + self.item7030 = ttk.Button(self.item7000, + text=_('Valider '), + command=self.surfOK) # bouton permettant de tout valider + self.item7031 = ttk.Button(self.item7000, + text=_(' Annuler'), + command=self.surfKO) # bouton permettant de tout annuler + + + + self.item7010.pack(pady=5) + for t,m in self.modes_interpol: + b = ttk.Radiobutton(self.item7000, text=t, variable=self.methode_interpol, value=m) + b.pack() + if(t == _("linéaire")): + b.state(['selected']) + self.methode_interpol.set("linear") + + + self.item7020.pack(pady=3) + self.item7021.pack(pady=5) + self.item7030.pack(pady=5) + self.item7031.pack(pady=5) + + # choix du profil utilisé à afficher (Idices surfaciques) + + self.num_profil = tkinter.StringVar() + self.num_profil.set("") + + self.item8000 = ttk.Frame(fenetre) + self.item8010 = ttk.Label(self.item8000, + text="\n" + _("Choisir profil à afficher ")) + self.item8011 = ttk.Entry(self.item8000, + textvariable=self.num_profil) + self.item8020 = ttk.Button(self.item8000, + text=_('Valider '), + command=self.affOK) # bouton permettant de tout valider + self.item8021 = ttk.Button(self.item8000, + text=_('Annuler '), + command=self.affK0) # bouton permettant de tout valider + self.item8010.pack(pady=3) + self.item8011.pack(pady=5) + self.item8020.pack(pady=5) + self.item8021.pack(pady=5) + + # La fenetre des options pour l'exif : + + self.exifMaker = tkinter.StringVar() + self.exifFocale35 = tkinter.StringVar() + self.exifFocale = tkinter.StringVar() + self.exifNomCamera = tkinter.StringVar() + + self.exifMaker.set("") + self.exifFocale35.set("") + self.exifFocale.set("") + self.exifNomCamera.set("") + + self.item3000 = ttk.Frame(fenetre) + self.item3010 = ttk.Label(self.item3000, + text=_("Modification des Exif") + "\n\n" + _("Marque de l'appareil : ")) + self.item3011 = ttk.Entry(self.item3000, + textvariable=self.exifMaker) + self.item3001 = ttk.Label(self.item3000, + text=_("Modèle de l'appareil: ")) + self.item3002 = ttk.Entry(self.item3000, + textvariable=self.exifNomCamera) + self.item3003 = ttk.Label(self.item3000, + text= _("Focale en mm:")) + self.item3004 = ttk.Entry(self.item3000, + textvariable=self.exifFocale) + self.item3005 = ttk.Label(self.item3000, + text= _("Focale équivalente 35mm :")) + self.item3006 = ttk.Entry(self.item3000, + textvariable=self.exifFocale35) + + self.item3020 = ttk.Button(self.item3000, + text=_('Valider et mettre à jour'), + command=self.exifOK) # bouton permettant de tout valider + self.item3021 = ttk.Button(self.item3000, + text=_(' Annuler'), + command=self.exifKO) # bouton permettant de tout annuler + + self.item3010.pack(pady=5) + self.item3011.pack(pady=1) + self.item3001.pack(pady=5) + self.item3002.pack(pady=1) + self.item3003.pack(pady=5) + self.item3004.pack(pady=1) + self.item3005.pack(pady=5) + self.item3006.pack(pady=1) + self.item3020.pack(pady=5) + self.item3021.pack(pady=5) + + # La boite de dialogue pour demander le nombre de photos a retenir parmi les meilleures + + self.item9000 = ttk.Frame(fenetre) + self.item9001 = ttk.Label(self.item9000) + self.item9002 = ttk.Label(self.item9000, + text= _("Indiquer le nombre de photos à retenir.") + "\n"+ + _("Un nouveau chantier sera créé avec les photos ayant, par paire, le plus de points homologues")+ "\n"+ + _("Ce choix est différent du nombre moyen de points homologues par photo.")) + self.item9003 = ttk.Entry(self.item9000) + self.item9004 = ttk.Button(self.item9000, + text=_(' Valider'), + command=self.nbMeilleuresOK) # bouton permettant de tout valider + self.item9005 = ttk.Button(self.item9000, + text=_(' Annuler'), + command=self.nbMeilleuresKO) # bouton permettant de tout annuler + self.item9001.pack(pady=15) + self.item9002.pack(pady=15) + self.item9003.pack(pady=15) + self.item9004.pack(pady=15) + self.item9005.pack(pady=15) + + # les logo, l'apropos + + self.logo1 = ttk.Frame(fenetre) # cadre dans la fenetre de départ : CEREMA ! + self.logo = ttk.Frame(self.resul100) # logo cerema dans l'apropos + self.canvasLogo = tkinter.Canvas(self.logo,width = 225, height = 80) # Canvas pour revevoir l'image + self.logoIgn = ttk.Frame(self.resul100) # logo IGN dans l'apropos + self.canvasLogoIGN = tkinter.Canvas(self.logoIgn,width = 149, height = 162)# Canvas pour revevoir l'image + self.labelIgn = ttk.Label(self.logo,text=_("MicMac est une réalisation de l'IGN")) # Les fichiers XML : - # fichier XML de description du masque + # fichier XML de description du masque - self.masqueXML = ( '\n'+ + self.masqueXMLOriginal = ( '\n'+ "\n"+ "MonImage_Masq.tif\n"+ "largeur hauteur\n"+ @@ -1326,9 +2325,9 @@ def initialiseConstantes(self): # Fichier de persistance des paramètres self.paramChantierSav = 'ParamChantier.sav' - self.fichierParamMicmac = os.path.join(self.repertoireScript,'ParamMicmac.sav') # sauvegarde des paramètres globaux d'AperodeDenis - self.fichierParamChantierEnCours= os.path.join(self.repertoireScript,self.paramChantierSav) # pour les paramètres du chantier en cours - + self.fichierParamMicmac = os.path.join(self.repertoireData,'ParamMicmac.sav') # sauvegarde des paramètres globaux d'AperodeDenis + self.fichierParamChantierEnCours= os.path.join(self.repertoireData,self.paramChantierSav) # pour les paramètres du chantier en cours + self.fichierSauvOptions = os.path.join(self.repertoireData,'OptionsMicmac.sav') # pour la sauvegarde d'options personnalisées # Divers @@ -1336,20 +2335,28 @@ def initialiseConstantes(self): self.logoIGN = os.path.join(self.repertoireScript,'logoIGN.jpg') self.messageNouveauDepart = str() # utilisé lorsque l'on relance la fenêtre self.nbEncadre = 0 # utilisé pour relancer la fenetre - + self.suffixeExport = "_export" # ne pas modifierr : rendra incompatible la nouvelle version + + self.messageSauvegardeOptions = (_("Quelles options par défaut utiliser pour les nouveaux chantiers ?") + "\n"+ + _("Les options par défaut concernent :") + "\n"+ + _("Tapioca : All, MulScale, line ,les échelles et delta") + "\n"+ + _("Tapas : RadialExtended,RadialStandard, Radialbasic, arrêt aprés Tapas") + "\n"+ + _("Malt : mode, zoom final, nombre de photos autour de la maîtresse") + "\n"+ + _("Tawny et ses options en saisie libre") + "\n"+ + _("C3DC : mode (Statue ou QuickMac)") + "\n\n") + self.tacky = True # Suite au message de Luc Girod sur le forum le 21 juin 17h + self.chantierNettoye = False # par défaut : le chantier n'est pas nettoyé ! + + ####################### initialiseValeursParDefaut du défaut : nouveau chantier, On choisira de nouvelles photos : on oublie ce qui précéde, sauf les paramètres généraux de aperodedenis (param micmac) + def initialiseValeursParDefaut(self): - - # Numéro du chantier : pour indicer le numéro du répertoire de travail : un nouveau est créé à chaque éxécution - - try: self.indiceTravail += 1 # on incrémente s'il existe - except: self.indiceTravail = 1 # sinon met à 1 sinon - # le chantier : variable self.etatDuChantier + # Etat du chantier : variable self.etatDuChantier # 0 : en cours de construction, pas encore de photos # 1 : photos saisies, répertoire origine fixé, non modifiable # 2 : chantier enregistré - # 3 : micmac lancé, pendant l'exécution de Tapioca et tapas + # 3 : micmac lancé, pendant l'exécution de Tapioca et tapas, reste si plantage # 4 : arrêt aprés tapas et durant malt en cours d'exécution # 5 : malt terminé # 6 : rendu modifiable aprés une première exécution @@ -1357,69 +2364,92 @@ def initialiseValeursParDefaut(self): self.etatDuChantier = 0 + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + + self.typeDuChantier = ['photos','initial','original'] + # La sauvegarde : self.etatSauvegarde # "" : lorsque le chantier est sauvegardé sous son répertoire de travail, l'exécution de micMac sauve le chantier # "*" : lors de sa création avant sauvegarde et lorsque le chantier a été modifié par l'utilisateur. self.etatSauvegarde = "" # Indicateur du caractère sauvegardé ("") ou à sauvegarder ("*") du chantier. utile pour affichage title fenetre - - # les photos : - + # Faut-il avertir l'utilisateur qu'il y a une nouvelle version disponible sur GitHub - self.repertoireDesPhotos = 'Pas de répertoire pour les photos' + self.avertirNouvelleVersion = False + + # les photos : + + self.repertoireDesPhotos = _('Pas de répertoire pour les photos') self.photosAvecChemin = list() # liste des noms des fichiers photos avec chemin complet self.photosSansChemin = list() # nom des photos sans le chemin - self.photosPropresAvecChemin = list() # les photos propres = photos à copier : on remplace les photos "sales" par les "propres" (nettoyées) self.lesExtensions = str() # l'utilisateur pourrait sélectionner des photos avec des extensions différentes - self.repTravail = self.repertoireScript # répertoire ou seront copiés les photos et ou se fera le traitement,Pour avoir un répertoire valide au début + self.repTravail = self.repertoireData # répertoire ou seront copiés les photos et ou se fera le traitement,Pour avoir un répertoire valide au début self.chantier = str() # nom du chantier (répertoire sosu le répertoire des photos) self.extensionChoisie = str() # extensions des photos (actuellement JPG obligatoire) - # Malt : Mode, Maitre et Masque : - - self.modeMalt.set('GeomImage') - self.masque = str() # nom du fichier image représentant le masque sur l'image maitresse - self.masqueSansChemin = str() # image masque : en TIF, choisi par l'utilisateur - self.maitreSansChemin = str() # image maitresse - self.maitreCommentaire = str() # indique si l'image maitresse est choisie automatiquement - self.maitre = str() - self.fichierMasqueXML = str() # nom du fichier XML décrivant le masque - self.nomMaitreSansExtension = str() - self.monImage_MaitrePlan = str() # Nom de l'image maitresse du plan repere (sans extension) - self.monImage_PlanTif = str() # nom du masque correspondant - self.planProvisoireHorizontal = "planHorizontal.tif" - self.planProvisoireVertical = "planVertical.tif" - - # mieux que Mic Mac qui prend par défaut le masque de l'image maitre avec le nom prédéfini masq - - + # Tapioca - self.modeTapioca.set('MulScale') - self.echelle1.set('500') - self.echelle2.set('500') - self.echelle3.set('1500') - self.echelle4.set('1500') - self.delta.set(1) + self.modeTapioca.set('MulScale')# Mode (All, MulScale, Line) + self.echelle1.set('1200') # echelle pour "All" + self.echelle2.set('300') # echelle base pour MulScale (si 2 photos n'ont qu'un seul point homologues a cette échelle la paire est ignorées dans l'étape suivante + self.echelle3.set('1200') # echelle haute pour MulScale + self.echelle4.set('1200') # echelle pour Line + self.delta.set('3') # delta en + et en = pour Line # TAPAS - self.modeCheckedTapas.set('RadialExtended') - self.arretApresTapas.set(1) # 1 : on arrête le traitement après Tapas, 0 on poursuit - + self.modeCheckedTapas.set('RadialBasic') # mode par défaut depuis la v 2.23 du 14 mars 2016 + self.arretApresTapas.set(1) # 1 : on arrête le traitement après Tapas, 0 on poursuit + self.lancerTarama.set(0) # 0 : on ne lance pas Tarama (mosaique des photos aprés Tapas) + self.photosPourCalibrationIntrinseque = list() # quelques images pour calibrer Tapas + self.calibSeule.set(False) # par défaut on exploite toutes les photos + self.mosaiqueTaramaTIF = str() + self.mosaiqueTaramaJPG = str() + self.masqueTarama = str() + # Malt + # mieux que Mic Mac qui prend par défaut le masque de l'image maitre avec le nom prédéfini masq - self.modeMalt.set('GeomImage') - + self.modeMalt.set('GeomImage') # par défaut + self.photosUtilesAutourDuMaitre.set(5) # 5 autour de l'image maîtresse (les meilleures seront choisies en terme de points homologues) + self.tawny.set(0) # pas de lancement par défaut de Tawny aprés Malt Ortho + self.tawnyParam.set("") # paramètres pour tawny + self.zoomF.set('4') # doit être "1","2","4" ou "8" (1 le plus détaillé, 8 le plus rapide) + self.etapeNuage = "5" # par défaut (très mystérieux!) + self.modele3DEnCours = "modele3D.ply" # Nom du self.modele3DEnCours courant + self.dicoInfoBullesAAfficher = None # pour passer l'info à afficherLesInfosBullesDuDico (dans choisirUnePhoto) + self.listeDesMaitresses = list() + self.listeDesMasques = list() + self.densification = "" # la densification en cours : Malt ou C3DC + self.zoomI = "" # le niveau de zoom initial en reprise de Malt + self.listeDesMaitressesApero = list() # les maitresses pour l'option AperoDeDenis (recalculées en fonction du répertoire Homol) + self.reinitialiseMaitreEtMasque() # initialise toutes les variables lièes à l'image maitresse et au masque + + #Tawny + + self.orthoMosaiqueTawny = "OrthoMosaique.tif" + + # C3DC + + self.modeC3DC.set("Statue") # valeur possible : Statue, Ground, QuickMac + # Calibration self.listePointsGPS = list() # 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) self.idPointGPS = 0 # identifiant des points, incrémenté de 1 a chaque insertion self.dicoPointsGPSEnPlace = dict() # dictionnaire des points GPS placés dans les photos (créé par la classe CalibrationGPS) - self.dicoLigneHorizontale = dict() # les deux points de la ligne horizontale (sur 2 photos) - self.dicoLigneVerticale = dict() # les 2 points décrivant une ligne horizontale + self.dicoLigneHorizontale = dict() # les deux points de la ligne horizontale + self.dicoLigneVerticale = dict() # les 2 points décrivant une ligne self.dicoCalibre = dict() # les 2 points décrivant un segment de longueur donnée + self.planProvisoireHorizontal = "planHorizontal.tif" + self.planProvisoireVertical = "planVertical.tif" + self.dicoPointsAAfficher = None # pour passer l'info à afficherTousLesPointsDuDico (dans choisirUnePhoto) + self.listeWidgetGPS = str() # liste des widgets pour la saisie # pour la trace : @@ -1427,393 +2457,631 @@ def initialiseValeursParDefaut(self): self.ligneFiltre = str() self.TraceMicMacComplete = str() self.TraceMicMacSynthese = str() - self.fichierParamChantier = "" #fichier paramètre sous le répertoire du chantier + self.fichierParamChantier = "" #fichier paramètre sous le répertoire du chantier + # divers - self.messageSiPasDeFichier = 1 # pour affichage de message dans choisirphoto, difficile a passer en paramètre - if self.systeme=="posix": # dépend de l'os, mais valeur par défaut nécessaire + self.messageSiPasDeFichier = 1 # pour affichage de message dans choisirphoto, difficile a passer en paramètre + if self.systeme=="posix": # dépend de l'os, mais valeur par défaut nécessaire self.shell = False if self.systeme=="nt": self.shell = True + self.homolActuel = str() # nom du répertoire qui a été renommé en "Homol" + self.fermetureOngletsEnCours = False # pour éviter de boucler sur la fermeture de la boite à onglet + self.fermetureOptionsGoProEnCours= False + self.fermetureModifExif = False - ################# Le Menu FICHIER : Ouvre un nouveau chantier avec les valeurs par défaut, ouvre un chantier existant, enregistrer, renommer, supprimer + # si les options par défaut sont personnalisées on les restaure : + + self.restaureOptions() - def nouveauChantier(self): # on conserve : micMac,meshlab,tousLesRepertoiresDeTravail - texte="" + ################# Le Menu FICHIER : Ouvre un nouveau chantier avec les valeurs par défaut, ouvre un chantier existant, enregistrer, renommer, supprimer + + # Enregistre le chantier précédent, prépare un chantier vide avec le répertoire de travail par défaut + + def nouveauChantier(self): # conserve : micMac,meshlab,tousLesRepertoiresDeTravail + self.menageEcran() + texte="" # réinitialise les paramètres du chantier (initialiseValeursParDefaut) if self.etatDuChantier == 1 : - if self.deuxBoutons("Enregistrer le chantier ?", - "Chantier non encore enregistré. Voulez-vous l'enregistrer ?", - "Enregistrer", - "Ne pas enregistrer.") == 0: + if self.troisBoutons(_("Enregistrer le chantier ?"), + _("Chantier non encore enregistré. Voulez-vous l'enregistrer ?"), + _("Enregistrer"), + _("Ne pas enregistrer.")) == 0: self.enregistreChantier() - texte="Chantier précédent enregistré : "+self.chantier+"\n" + texte=_("Chantier précédent enregistré : %s") % (self.chantier)+ "\n" if self.etatDuChantier >= 2 and self.etatSauvegarde =="*": - if self.deuxBoutons("Enregistrer le chantier "+self.chantier+" ?", - "Chantier modifé depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?", - "Enregistrer", - "Ne pas enregistrer.") == 0: + if self.troisBoutons(_("Enregistrer le chantier %s ?") % (self.chantier), + _("Chantier modifié depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?"), + _("Enregistrer"), + _("Ne pas enregistrer.")) == 0: self.copierParamVersChantier() - texte = "Chantier précédent enregistré : "+self.chantier+"\n" + texte = _("Chantier précédent enregistré : %s") % (self.chantier)+ "\n" self.initialiseValeursParDefaut() os.chdir(self.repTravail) # lors de la création d'un chantier il s'agir du répertoire de l'appli self.afficheEtat(texte) - - + def ouvreChantier(self): + self.menageEcran() texte="" - if self.etatDuChantier == 1 : - if self.deuxBoutons("Enregistrer le chantier ?", - "Chantier non encore enregistré. Voulez-vous l'enregistrer ?", - "Enregistrer", - "Ne pas enregistrer.") == 0: + if self.etatDuChantier == 1 and self.etatSauvegarde =="*": + if self.troisBoutons(_("Enregistrer le chantier ?"), + _("Chantier non encore enregistré. Voulez-vous l'enregistrer ?"), + _("Enregistrer"), + _("Ne pas enregistrer.")) == 0: self.enregistreChantier() - texte="Chantier précédent enregistré : "+self.chantier+"\n" + texte=_("Chantier précédent enregistré : %s") % (self.chantier) + "\n" if self.etatDuChantier >= 2 and self.etatSauvegarde =="*": - if self.deuxBoutons("Enregistrer le chantier "+self.chantier+" ?", - "Chantier modifé depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?", - "Enregistrer", - "Ne pas enregistrer.") == 0: + if self.troisBoutons(_("Enregistrer le chantier %s ?") % (self.chantier), + _("Chantier modifié depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?"), + _("Enregistrer"), + _("Ne pas enregistrer.")) == 0: self.copierParamVersChantier() - texte="Chantier précédent enregistré : "+self.chantier+"\n" - - bilan = self.choisirUnRepertoire("Choisir un chantier.") # boite de dialogue de sélection du chantier à ouvrir, renvoi : self.selectionRepertoireAvecChemin + texte=_("Chantier précédent enregistré : %s") % (self.chantier) + "\n" + bilan = self.choisirUnChantier(_("Choisir un chantier.")) # boite de dialogue de sélection du chantier à ouvrir, renvoi : self.selectionRepertoireAvecChemin if bilan!=None: - self.afficheEtat("Aucun chantier choisi.\n"+bilan+"\n") + self.afficheEtat(_("Aucun chantier choisi.") + "\n" + bilan + "\n") return - self.fichierParamChantier = self.selectionRepertoireAvecChemin+os.sep+self.paramChantierSav + self.fichierParamChantier = os.path.join(self.selectionRepertoireAvecChemin,self.paramChantierSav) if os.path.exists(self.fichierParamChantier): - self.restaureParamChantier(self.fichierParamChantier) - self.etatSauvegarde = "" + self.restaureParamChantier(self.fichierParamChantier) self.sauveParam() # pour assurer la cohérence entre le chantier en cours et le chantier ouvert (écrase le chantier en cours) self.afficheEtat(texte) else: - self.encadre ('Chantier choisi "'+self.selectionRepertoireAvecChemin+'" corrompu. Abandon.') + self.encadre (_('Chantier choisi %s corrompu. Abandon.') % (self.selectionRepertoireAvecChemin),nouveauDepart='non') + def enregistreChantierAvecMessage(self): + if(self.enregistreChantier()): + self.afficheEtat(_("Chantier enregistré")) def enregistreChantier(self): # Correspond simplement à la copie du fichier paramètre sous le répertoire de travail et à l''apparition du nom + self.menageEcran() if self.etatDuChantier == 0: # pas de photo : pas d'enregistrement - self.encadre("Indiquer les photos à traiter avant d'enregistrer le chantier.") - return + self.encadre(_("Indiquer les photos à traiter avant d'enregistrer le chantier."),nouveauDepart="non") + return False if self.etatDuChantier == 1: # des photos, pas encore enregistré : on mote l'enregistrement : etat = 2 self.etatDuChantier = 2 self.copierParamVersChantier() # on enregistre, ou on réenregistre + return True def renommeChantier(self): + self.menageEcran() if self.etatDuChantier==0: - self.encadre("Le chantier est en cours de définition.\nIl n'a pas encore de nom, il ne peut être renommé.\n\nCommencer par choisir les photos") - return - texte = "Nouveau nom pour le chantier "+self.chantier+" :\n" - bas = "Un chemin, absolu ou relatif, est un nom valide\n\nAucun fichier de l'arborecence du chantier ne soit être ouvert." - if self.etatSauvegarde=="*": - bas = bas+"\nLe chantier, actuellement modifié, sera enregistré." + self.encadre(_("Le chantier est en cours de définition.") + "\n" + _("Il n'a pas encore de nom, il ne peut être renommé.") + "\n\n" + _("Commencer par choisir les photos"),nouveauDepart='non') + return + texte = _("Nouveau nom ou nouveau chemin pour le chantier %s :") % (self.chantier) + "\n" + bas = (_("Tout chemin relatif au chemin actuel est valide") + "\n\n"+ + _("Un chemin absolu sur la même unité disque est valide") + "\n\n"+ + _("Aucun fichier de l'arborescence du chantier ne doit être ouvert.")) + new = MyDialog(fenetre,texte,basDePage=bas) - if new.saisie!="": - nouveauRepertoire = os.path.join(self.repertoireDesPhotos,new.saisie) - if os.path.splitdrive(nouveauRepertoire)[0].upper()!=os.path.splitdrive(self.repTravail)[0].upper(): - self.encadre("Le nom \n\n"+new.saisie+"\n\nimplique un changement de disque.\nCette version ne permet pas cette opération.") - return - if os.path.exists(nouveauRepertoire): - self.encadre("Le nom \n"+new.saisie+"\npour le chantier est déjà utilisé.\nChoississez un autre nom.") - return - self.fermerVisuPhoto() # fermer tous les fichiers potentiellement ouvert. - os.chdir(self.repertoireScript) # quitter le répertoire courant - try: - self.meshlabExe1.kill() - time.sleep(0.1) - except: pass # fermer meshlab si possible - try: - self.meshlabExe2.kill() - time.sleep(0.1) - except: pass - try: - time.sleep(0.1) - os.rename (self.repTravail,nouveauRepertoire) # RENOMMER + if new.saisie=="": + return + if self.repertoireDesPhotos==self.repTravail: # le le répertoire des photos est = répertoire de travail alors on renomme au même niveau d'arborescence + nouveauRepertoire = os.path.normcase(os.path.normpath(os.path.join(os.path.dirname(self.repertoireDesPhotos),new.saisie))) + else: # sinon on renomme sous le répertoire des photos + nouveauRepertoire = os.path.normcase(os.path.normpath(os.path.join(self.repertoireDesPhotos,new.saisie))) + nouveauChantier = os.path.basename(nouveauRepertoire) + if nouveauChantier.upper() in [os.path.basename(e).upper() for e in self.tousLesChantiers]: + self.encadre(_("Le nom du nouveau chantier %s existe déjà. Abandon.") % (nouveauChantier),nouveauDepart='non') + return + if os.path.splitdrive(nouveauRepertoire)[0].upper()!=os.path.splitdrive(self.repTravail)[0].upper(): + self.encadre(_("Le nouveau répertoire ") + "\n\n" + nouveauRepertoire + "\n\n" + _("implique un changement de disque.") + "\n" + _("Utiliser l'Export-Import."),nouveauDepart='non') + return + if os.path.exists(nouveauRepertoire): + self.encadre(_("Le répertoire") + "\n" + nouveauRepertoire + "\n" + _("pour le chantier est déjà utilisé.") + "\n" + _("Choisissez un autre nom."),nouveauDepart='non') + return + if self.repTravail in nouveauRepertoire: + self.encadre(_("Le répertoire") + "\n" + nouveauRepertoire + "\n" + _("désigne un sous-répertoire du chantier en cours.") + "\n" + _("Choisissez un autre nom."),nouveauDepart='non') + return + self.fermerVisuPhoto() # fermer tous les fichiers potentiellement ouvert. + os.chdir(self.repertoireData) # quitter le répertoire courant + try: self.meshlabExe1.kill() + except: pass # fermer meshlab si possible + try: self.meshlabExe2.kill() + except: pass + try: + time.sleep(0.1) + os.renames (self.repTravail,nouveauRepertoire) # RENOMMER + except Exception as e: + self.encadre(_("Le renommage du chantier ne peut se faire actuellement,") + "\n" + _("soit le nom fourni est incorrect,") + "\n"+ + _("soit un fichier du chantier est ouvert par une autre application.") + "\n"+ + _("soit l'explorateur explore l'arborescence.") + "\n" + _("erreur : ") + "\n\n"+str(e),nouveauDepart='non') + return + + ancienChantier = self.chantier + self.chantier = nouveauChantier + try: self.tousLesChantiers.remove(self.repTravail) # retirer l'ancien nom de la liste des répertoires de travail + except: pass + self.repTravail = nouveauRepertoire # positionner le nouveau nom + self.redefinirLesChemins() # mettre à jour le nom de tous les chemins realtifs + ajout(self.tousLesChantiers,self.repTravail) # ajouter le nouveau nom parmi les noms de chantiers + # Type de chantier : self.typeDuChantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + self.typeDuChantier[1] = 'renommé' + + self.encadreEtTrace("\n---------\n"+ heure() + "\n" + _("Chantier :") + "\n" + ancienChantier + "\n" + _("renommé en :") + "\n" + self.chantier + "\n" + _("Répertoire : ") + self.repTravail + "\n") + + def redefinirLesChemins(self): # Mettre self.repTravail dans les chemins des images maitre et masques et dans les dictionnaires, sauver + # si le chantier n'est plus sous le répertoire des photos alors le répertoire des photos devient le chantier lui même + + self.listeDesMaitresses = [os.path.join(self.repTravail,os.path.basename(afficheChemin(e))) for e in self.listeDesMaitresses] + self.listeDesMasques = [os.path.join(self.repTravail,os.path.basename(afficheChemin(e))) for e in self.listeDesMasques] + + if self.fichierMasqueXML!=str(): + self.fichierMasqueXML = os.path.join(self.repTravail,os.path.basename(afficheChemin(self.fichierMasqueXML))) + if self.monImage_MaitrePlan!=str(): + self.monImage_MaitrePlan = os.path.join(self.repTravail,os.path.basename(afficheChemin(self.monImage_MaitrePlan))) + self.monImage_PlanTif = os.path.join(self.repTravail,os.path.basename(afficheChemin(self.monImage_PlanTif))) + + self.photosAvecChemin = [os.path.join(self.repTravail,os.path.basename(afficheChemin(e))) for e in self.photosAvecChemin] + + # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + dico=dict() + for e in self.dicoPointsGPSEnPlace.keys(): + f = (e[0],os.path.join(self.repTravail,os.path.basename(afficheChemin(e[1]))),e[2]) + dico[f]=self.dicoPointsGPSEnPlace[e] + self.dicoPointsGPSEnPlace = dict(dico) + + # axe horizontal, dans le dico : self.dicoLigneHorizontale. key = nom point, photo, identifiant ;Retrouver nom de la photo, coordonnées des points + # items = liste de tuple (key,values) soit tuple = (point,photo, id),(x1,y1) + + dico=dict() + for e in self.dicoLigneHorizontale.keys(): + f = (e[0],os.path.join(self.repTravail,os.path.basename(afficheChemin(e[1]))),e[2]) + dico[f]=self.dicoLigneHorizontale[e] + self.dicoLigneHorizontale = dict(dico) + dico=dict() + for e in self.dicoLigneVerticale.keys(): + f = (e[0],os.path.join(self.repTravail,os.path.basename(afficheChemin(e[1]))),e[2]) + dico[f]=self.dicoLigneVerticale[e] + self.dicoLigneVerticale = dict(dico) + dico=dict() + + for e in self.dicoCalibre.keys(): + f = (e[0],os.path.join(self.repTravail,os.path.basename(afficheChemin(e[1]))),e[2]) + dico[f]=self.dicoCalibre[e] + self.dicoCalibre = dict(dico) + + # nouveau répertoire des photos : + + self.repertoireDesPhotos = afficheChemin(self.repertoireDesPhotos) + + if not os.path.isdir(self.repertoireDesPhotos): + self.repertoireDesPhotos = self.repTravail + + self.definirFichiersTrace() # positionne sous le répertoire de travail + self.copierParamVersChantier() # sauve param puis copie cers chantier en cours + + def exporteChantier(self): + self.menageEcran() + if self.etatDuChantier == 0: + self.encadre(_("Pas de chantier en cours"),nouveauDepart='non') + return + self.encadre(_("Patience : chantier en cours d'archivage...") + "\n",nouveauDepart='non') + self.copierParamVersChantier() # enregistre et sauve le chantier + self.encadre(_("Archive ") + "\n" + self.chantier + ".exp" + "\n" + _("créée sous ") + "\n" + self.repTravail + "\n\n" + _("Taille =") + str(int(zipdir(self.repTravail)/1024)) + "Ko") + + def importeChantier(self): + self.menageEcran() + try: + self.encadre(_("Choisir le nom de l'archive à importer."),nouveauDepart='non') + archive = tkinter.filedialog.askopenfilename( initialdir=self.repTravail, + filetypes=[(_("Export"),"*.exp"),(_("Tous"),"*")],multiple=False, + title = _("Chantier à importer")) + if archive==str(): + self.encadre(_("Importation abandonnée."),nouveauDepart='non') + return + if not zipfile.is_zipfile(archive): + self.encadre(archive+_(" n'est pas un fichier d'export valide") + "\n"+ + _("ou alors, sous ubuntu,il lui manque le droit d'exécution."), + nouveauDepart='non') + return + + self.encadre(_("Choisir le répertoire dans lequel recopier le chantier."),nouveauDepart='non') + destination = tkinter.filedialog.askdirectory(title='Désigner le répertoire où importer le chantier ', + initialdir=self.repTravail) + if not os.path.isdir(destination): + self.encadre(destination+_(" n'est pas un répertoire valide."),nouveauDepart='non') + return + os.chdir(destination) # relativise les chemins + self.encadre(_("Recopie en cours dans") + "\n" + destination + "\n" + _("Patience !"),nouveauDepart='non') + + zipf = zipfile.ZipFile(archive, 'r') # ouverture du zip + # récupération du nom du futur chantier : c'est la racine commune de tous les fichiers dans la sauvegarde + nouveauChantier = os.path.normpath(os.path.commonprefix(zipf.namelist())[:-1]) + ancienChantier = nouveauChantier.split(self.suffixeExport)[0] # ancien chantier = nouveau - suffixe + if os.path.isdir(nouveauChantier): + zipf.close() + self.encadre(_("Le répertoire destination") + "\n" + os.path.join(destination, nouveauChantier) + "\n" + _("existe déjà. Abandon"),nouveauDepart='non') + return + zipf.extractall(path=destination) + zipf.close() + oldChantier = nouveauChantier + i = 0 + while (os.path.basename(nouveauChantier) in [os.path.basename(e) for e in self.tousLesChantiers]) or os.path.isdir(os.path.join(destination,nouveauChantier)) and i<20: + nouveauChantier = nouveauChantier+"x" + i += 1 + try: os.renames (oldChantier,nouveauChantier) # on a trouvé un nom nouveau de chantier ET de répertoire (plante si old=nouveau) except Exception as e: - self.encadre("Le renommage du chantier ne peut se faire actuellement,\nsoit le nom fourni est incorrect,\n"+ - "soit un fichier du chantier est ouvert par une autre application.\n"+ - "soit l'explorateur explore l'arborescence.\nerreur : \n\n"+str(e)) + print(_("Erreur copie lors d'un import : "),str(e)) + self.encadre(_("L'importation a échouée. Erreur : ")+str(e),nouveauDepart='non') return - self.tousLesChantiers.remove(self.repTravail) # retirer de la liste des répertoires de travail - ajout(self.tousLesChantiers,nouveauRepertoire) # ajouter le nouveau - ancienChantier = self.chantier - self.repTravail = nouveauRepertoire # maj des paramètres + + nouveauChemin = os.path.normcase(os.path.normpath(os.path.join(destination,nouveauChantier))) + + # on copie si possible l'archive sous le nouveau répertoire de travail + try: shutil.copy(archive,nouveauChemin) + except Exception as e: + print(_("Erreur copie lors d'un import : "),str(e)) + self.encadre(_("L'importation a échouée. Erreur : ")+str(e),nouveauDepart='non') + return + # le répertoire des photos devient le répertoire de travail - #redéfinir les chemins des images maitre et masques + # on ajoute le chantier dans les paramètres généraux - if self.maitre!=str(): - self.maitre = os.path.join(self.repTravail,self.maitreSansChemin) - if self.masque!=str(): - self.masque = os.path.join(self.repTravail,self.masqueSansChemin) - if self.fichierMasqueXML!=str(): - self.fichierMasqueXML = os.path.join(self.repTravail,os.path.basename(self.fichierMasqueXML)) - if self.monImage_MaitrePlan!=str(): - self.monImage_MaitrePlan = os.path.join(self.repTravail,os.path.basename(self.monImage_MaitrePlan)) - self.monImage_PlanTif = os.path.join(self.repTravail,os.path.basename(self.monImage_PlanTif)) - - self.photosPropresAvecChemin = [os.path.join(self.repTravail,os.path.basename(e)) for e in self.photosPropresAvecChemin] + ajout(self.tousLesChantiers,nouveauChemin) # ajouter le nouveau + self.sauveParamMicMac() - # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y - print("avant : ",self.dicoPointsGPSEnPlace) - dico=dict() - for e in self.dicoPointsGPSEnPlace.keys(): - f = (e[0],os.path.join(self.repTravail,os.path.basename(e[1])),e[2]) - dico[f]=self.dicoPointsGPSEnPlace[e] - self.dicoPointsGPSEnPlace = dict(dico) - print("aprés : ",self.dicoPointsGPSEnPlace) - - # axe horizontal, dans le dico : self.dicoLigneHorizontale. key = nom point, photo, identifiant ;Retrouver nom de la photo, coordonnées des points - # items = liste de tuple (key,values) soit tuple = (point,photo, id),(x1,y1) - - print("avant : ",self.dicoLigneHorizontale) - dico=dict() - for e in self.dicoLigneHorizontale.keys(): - f = (e[0],os.path.join(self.repTravail,os.path.basename(e[1])),e[2]) - dico[f]=self.dicoLigneHorizontale[e] - self.dicoLigneHorizontale = dict(dico) - print("aprés : dicoLigneHorizontale",self.dicoLigneHorizontale) - - print("avant : ",self.dicoLigneVerticale) - dico=dict() - for e in self.dicoLigneVerticale.keys(): - f = (e[0],os.path.join(self.repTravail,os.path.basename(e[1])),e[2]) - dico[f]=self.dicoLigneVerticale[e] - self.dicoLigneVerticale = dict(dico) - print("aprés dicoLigneVerticale: ",self.dicoLigneVerticale) - - print("avant : ",self.dicoCalibre) - dico=dict() - for e in self.dicoCalibre.keys(): - f = (e[0],os.path.join(self.repTravail,os.path.basename(e[1])),e[2]) - dico[f]=self.dicoCalibre[e] - self.dicoCalibre = dict(dico) - print("aprés dicoCalibre: ",self.dicoCalibre) + # on met à jour les paramètres locaux : remplacer les répertoires ancien par le nouveau, sauvegarder + fichierParam = os.path.join(nouveauChemin,self.paramChantierSav) + + if os.path.isfile(fichierParam): + self.restaureParamChantier(fichierParam) # la restauration positionne self.reptravail et self.chantier sur l'ancien répertoire de travail + else: + self.encadre(fichierParam+_(" absent"),nouveauDepart='non') + return + self.repTravail = nouveauChemin + self.chantier = nouveauChantier + self.definirFichiersTrace() # la restauration a défini des chemins suivant l'ancien reptravail : il faut corriger + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + self.typeDuChantier[2] = 'importé' + self.redefinirLesChemins() # mise à jour des chemins et sauvegarde des paramètres. - self.chantier = new.saisie - self.definirFichiersTrace() #positionne sous le répertoire de travail - self.copierParamVersChantier() # sauve param puis copie on enregistre, ou on réenregistre - self.afficheEtat("Chantier :\n"+ancienChantier+"\nrenommé en :\n"+self.chantier+"\n") + # on affiche l'état du chantier : + self.encadreEtTrace("\n\n -------------- \n"+ + heure()+ + "\n" + _("Chantier importé :") + "\n" + self.chantier + "\n\n" + _("Répertoire :") + "\n" +self.repTravail+ "\n\n" + _("Vous pouvez le renommer si besoin.")+ + "\n -------------- ") + try: + self.ajoutLigne("\n" + _("Version de MicMac avant l'import : %s") % (self.mercurialMicMacChantier) +"\n") + self.ajoutLigne("\n" + _("Version de MicMac : %s") % (self.mercurialMicMac) +"\n") + self.ecritureTraceMicMac() + except Exception as e: + print(_("erreur affichage version lors de l'import d'un chantier : ")+str(e)) + except Exception as e: + self.encadre(_("Anomalie lors de l'importation : ")+str(e),nouveauDepart='non') + return + def copierParamVersChantier(self): # copie du fichier paramètre sous le répertoire du chantier, pour rejouer et trace try: - self.etatSauvegarde = "" # Pour indiquer que le chantier sauvegardé sous le répertoire du chantier + self.etatSauvegarde = "" self.sauveParam() - if self.repTravail!=os.path.dirname(self.fichierParamChantierEnCours): # pour éviter de copier un fichier sur lui même - shutil.copy(self.fichierParamChantierEnCours,self.repTravail) + try: shutil.copy(self.fichierParamChantierEnCours,self.repTravail) # pour éviter de copier un fichier sur lui même + except Exception as e: print(_("erreur copie fichier param chantier : %(param)s vers %(rep)s erreur=") % {"param" : self.fichierParamChantierEnCours, "rep" : self.repTravail} ,str(e)) fenetre.title(self.etatSauvegarde+self.titreFenetre) except Exception as e: - self.ajoutLigne("Erreur lors de la copy du fichier paramètre chantier \n"+self.fichierParamChantierEnCours+"\n vers \n"+self.repTravail+"\n erreur : \n"+e) + self.ajoutLigne(_("Erreur lors de la copie du fichier paramètre chantier") + "\n" + self.fichierParamChantierEnCours + "\n" + _("vers") + "\n" + self.repTravail + "\n" + _("erreur :") + "\n" +str(e)) ################################## LE MENU EDITION : afficher l'état, les photos, lire une trace, afficher les nuages de points ############################ def afficheEtat(self,entete="",finale=""): + if self.pasDeMm3d():return self.sauveParam() + self.avertissementNouvelleVersion() nbPly = 0 photosSansCheminDebutFin = list(self.photosSansChemin) + texte = str() if len(self.photosSansChemin)>5: photosSansCheminDebutFin =photosSansCheminDebutFin[:2]+list('..',)+photosSansCheminDebutFin[-2:] - try: # rappel des valeurs par défauts (try car erreur si le format de la sauvegarde a changé cela plante) : - texte = entete+'\nRépertoire des photos : \n'+afficheChemin(self.repertoireDesPhotos) + try: + # affiche les options du chantier (try car erreur si le format de la sauvegarde a changé cela plante) : + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + if self.typeDuChantier[0]=='photos': + texte = entete + '\n' + _('Répertoire des photos :') + "\n" + afficheChemin(self.repertoireDesPhotos) + if self.typeDuChantier[0]=='vidéo': + texte = entete + "\n" + _("Répertoire de la vidéo :") + "\n" + afficheChemin(self.repertoireDesPhotos) if len(self.photosSansChemin)==0: - texte = texte+'\n\n'+'Aucune photo sélectionnée.\n' - if len(self.photosSansChemin)>=1: # Il ne peut en principe pas y avoir une seule photo sélectionnée - texte = texte+'\n\n'+str(len(self.photosSansChemin))+' photos sélectionnées : \n' +\ - '\n'.join(photosSansCheminDebutFin)+finale + texte = texte+'\n\n'+_('Aucune photo sélectionnée.') + '\n' + if len(self.photosSansChemin)>=1: # Il ne peut en principe pas y avoir une seule photo sélectionnée + if self.calibSeule.get(): + m = _(' photos sélectionnées') + '\n' + _('(sans calibration si tapas executé) : ') + '\n' + else: + m = _(' photos sélectionnées : ') + '\n' + texte = texte+'\n\n'+str(len(self.photosSansChemin))+m+'\n'.join(photosSansCheminDebutFin)+finale if self.nombreDExtensionDifferentes(self.photosSansChemin)>1: # il y a plus d'un format de photo ! - texte = texte+'\n\nATTENTION : plusieurs extensions différentes dans les photos choisies !\n Le traitement ne se fera que sur un type de fichier.' + texte = texte+'\n\n' + _('ATTENTION : plusieurs extensions différentes dans les photos choisies !') + '\n' + _('Le traitement ne se fera que sur un type de fichier.') # Options pour Tapioca : if self.modeTapioca.get()!='': - texte = texte+'\n\nTapioca :\nMode : '+self.modeTapioca.get()+'\n' + texte = texte+'\n\n' + 'Tapioca :' + '\n' + _('Mode : ')+self.modeTapioca.get()+'\n' if self.modeTapioca.get()=="All": - texte = texte+'Echelle 1 : '+self.echelle1.get()+'\n' + texte = texte+_('Echelle 1 : ')+self.echelle1.get()+'\n' if self.modeTapioca.get()=="MulScale": - texte = texte+'Echelle 1 : '+self.echelle2.get()+'\n' - texte = texte+'Echelle 2 : '+self.echelle3.get()+'\n' + texte = texte+_('Echelle 1 : ')+self.echelle2.get()+'\n' + texte = texte+_('Echelle 2 : ')+self.echelle3.get()+'\n' if self.modeTapioca.get()=="Line": - texte = texte+'Echelle : '+self.echelle4.get()+'\n' - texte = texte+'Delta : '+self.delta.get()+'\n' + texte = texte+_('Echelle : ')+self.echelle4.get()+'\n' + texte = texte+_('Delta : ')+self.delta.get()+'\n' # Options pour Tapas : if self.modeCheckedTapas.get()!='': - texte = texte+'\nTapas :\nMode : '+self.modeCheckedTapas.get()+'\n' + texte = texte+'\n' + 'Tapas :\n' + _('Mode : ')+self.modeCheckedTapas.get()+'\n' + if self.photosPourCalibrationIntrinseque.__len__()>0: + texte = texte+_("Nombre de photos pour calibration intrinsèque : ")+str(self.photosPourCalibrationIntrinseque.__len__())+"\n" + if self.calibSeule.get(): + texte = texte+_('Ces photos servent uniquement à la calibration.') + '\n' + if self.lancerTarama.get()==1: + texte = texte+_('Tarama demandé aprés Tapas') + '\n' if self.arretApresTapas.get()==1: - texte = texte+'Arrêt demandé après Tapas\n' - + texte = texte+_('Arrêt demandé après Tapas') + '\n' + # Calibration if self.controleCalibration(): - texte = texte+'\nCalibration présente\n'+self.etatCalibration + texte = texte+'\n' + _('Calibration présente') + '\n'+self.etatCalibration else: if self.distance.get()=='0': - texte = texte+'\nCalibration annulée : distance=0\n' + texte = texte+'\n' + _('Calibration annulée : distance=0') + '\n' elif self.etatCalibration!=str(): # calibration incomplète - texte = texte+"\nCalibration incomplète :\n"+self.etatCalibration+"\n" + texte = texte+"\n" + _("Calibration incomplète :") + "\n"+self.etatCalibration+"\n" # Points GPS - - if self.controlePointsGPS(): - texte = texte+self.etatPointsGPS + + self.controlePointsGPS() + texte = texte+self.etatPointsGPS - # Masque 3D pour D3DC ou alors Malt et image maitresse et masque : + # Masque 3D pour D3DC ou alors Malt et image maîtresse et masque : + malt = True # a priori on éxécute malt if self.mm3dOK: # La version de MicMac autorise les masques 3D if self.existeMasque3D(): - texte = texte+'\nC3DC : Masque 3D\n' + texte = texte+'\n' + _('C3DC : Masque 3D') + '\n' malt = False # on éxécutera C3DC + self.densification = "C3DC" else: - texte = texte + "\nLa version installée de Micmac n'autorise pas les masques en 3D\n" + texte = texte + "\n" + _("La version installée de Micmac n'autorise pas les masques en 3D") + "\n" + + # Malt si pas c3dc if malt: - if self.maitreSansChemin!='': - texte = texte+'\nMalt :\nMode : '+self.modeMalt.get()+'\nImage maitresse : '+self.maitreSansChemin - else: - texte = texte+'\nMalt :\nMode : '+self.modeMalt.get()+"\nPas d'image maitresse." - if self.masqueSansChemin!='': - texte = texte+'\nMasque : '+self.masqueSansChemin+'\n' - else: - texte = texte+"\nPas de masque.\n" - + self.densification = "Malt" + texte = texte+'\n' + 'Malt :\n' + _('Mode : ')+self.modeMalt.get() + if self.modeMalt.get()=="GeomImage": + if self.listeDesMaitresses.__len__()==0: + texte = texte+"\n" + _("Pas d'image maîtresse") + if self.listeDesMaitresses.__len__()==1: + texte = texte+'\n' + _('Image maîtresse : ')+os.path.basename(self.listeDesMaitresses[0]) + if self.listeDesMaitresses.__len__()>1: + texte = texte+'\n'+str(self.listeDesMaitresses.__len__())+_(' images maîtresses') + if self.listeDesMasques.__len__()==1: + texte = texte+'\n' + _('1 masque') + '\n' + if self.listeDesMasques.__len__()==0 and self.listeDesMaitresses.__len__()>0: + texte = texte+"\n" + _("Pas de masque.") + "\n" + if self.listeDesMasques.__len__()>1: + texte = texte+"\n"+str(self.listeDesMasques.__len__())+_(" masques") + "\n" + if self.listeDesMaitresses.__len__()>0 and self.photosUtilesAutourDuMaitre.get()>0: + texte = texte+_("%s photos utiles autour de la maîtresse") %(str(self.photosUtilesAutourDuMaitre.get()))+"\n" + texte = texte+_("les meilleures photos en correspondances seront choisies")+ "\n" + + if self.modeMalt.get()=="Ortho": + if self.tawny.get(): + texte = texte+"\n" + _("Tawny lancé aprés Malt")+"\n" + + if self.modeMalt.get()=="AperoDeDenis": + if self.listeDesMaitressesApero.__len__()==1: + texte = texte+'\n' + _('Image maîtresse : ')+os.path.basename(self.listeDesMaitressesApero[0]) + if self.listeDesMaitressesApero.__len__()>1: + texte = texte+'\n' + str(self.listeDesMaitressesApero.__len__())+_(' images maîtresses') + + texte = texte+"\n" + _("arrêt au zoom : ")+self.zoomF.get()+"\n" + # état du chantier : if self.etatDuChantier == 0: # pas encore de chantier - texte = texte+"\nChantier en cours de définition.\n" - if self.etatDuChantier >= 1: # le chantier est créé : il y a des photos choisies (2 enregistré, - # 3 en cours d'exécution, - # 4 arrêt tapas, 5 terminé, 6 modifiable mais n'existe plus) - texte = texte+"\nChantier : "+self.chantier+".\n" - else: - texte = texte+"\nChantier en attente d'enregistrement.\n" - if self.etatDuChantier in (2,6) and self.etatSauvegarde=="": - texte = texte+"\nChantier enregistré.\n" - if self.etatDuChantier==2: - texte = texte+"Chantier modifiable.\n" - if self.etatDuChantier == 3: - texte = texte+"\nChantier interrompu.\nRelancer micmac.\n" - if self.etatDuChantier == 4: - texte = texte+"Arrêté aprés Tapas.\n" - if self.etatDuChantier == 5: - texte = texte+"Chantier terminé.\n" - if self.etatDuChantier == 6: - texte = texte+"\nChantier exécuté puis débloqué.\n" + texte = texte+"\n" + _("Chantier en cours de définition.") + "\n" + + + # un chantier avec des traitements effectués et pas de sous-répertoire : il a été nettoyé ! + + if self.etatDuChantier >= 3 and len([f for f in os.listdir(self.repTravail) if os.path.isdir(os.path.join(self.repTravail, f))])==0: + texte = texte+"\n" + _("Chantier nettoyé.") + "\n" + self.chantierNettoye = True + self.etatDuChantier = 2 + self.sauveParam() + + # chantier nettoyé mais relancé depuis : + + if self.chantierNettoye and self.etatDuChantier>=3: + self.chantierNettoye = False # le chantier a été relancé, n'est plus nettoyé + + # Message si chantier nettoyé non relancé : + + if self.chantierNettoye: + texte = texte+"\n" + _("Chantier nettoyé.") + "\n" + + # Affichage de l'état du chantier : + + if self.etatDuChantier >= 1: # le chantier est créé : il y a des photos choisies (2 enregistré, + # 3 en cours d'exécution, + # 4 arrêt aprés tapas, 5 terminé aprés malt ou c3dc, 6 modifiable mais n'existe plus) + texte = texte+"\n" + _("Chantier : ")+self.chantier+".\n" + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + + if self.typeDuChantier[1]=="renommé" or self.typeDuChantier[2]=="importé": + texte = texte + _("Chemin du chantier :") + "\n"+afficheChemin(os.path.dirname(self.repTravail))+"\n\n" + else: + texte = texte+"\n" + _("Chantier en attente d'enregistrement.") + "\n" + if self.etatDuChantier in (2,3,4,5,6) and self.etatSauvegarde=="": + texte = texte+"\n" + _("Chantier enregistré.") + "\n" + if self.etatDuChantier == "2": + texte = texte+_("Options du chantier modifiables.") + "\n" + if self.etatDuChantier == 3: + texte = texte+"\n" + _("Chantier interrompu suite à erreur.") + "\n" + _("Relancer micmac.") + "\n" + if self.etatDuChantier == 4: + texte = texte+_("Options de Malt/C3DC modifiables.") + "\n" + if self.etatDuChantier == 5: + texte = texte+_("Chantier terminé.")+ "\n" + if self.etatDuChantier == 6: + texte = texte+"\n" + _("Chantier exécuté puis débloqué.") + "\n" # Résultat des traitements : if os.path.exists('AperiCloud.ply'): - texte = texte+"Nuage de point non densifié généré après Tapas.\n" + texte = texte+_("Nuage de point non densifié généré après Tapas.") + "\n" nbPly=1 - if os.path.exists('modele3D.ply'): - texte = texte+"Nuage de point densifié généré après Malt ou C3DC.\n" + + if os.path.exists(self.modele3DEnCours): + texte = texte+_("Nuage de point densifié généré après %s") %(self.densification)+".\n" nbPly+=1 if self.etatDuChantier in (4,5,6) and nbPly==0: - texte = texte+"Aucun nuage de point généré.\n" + texte = texte+_("Aucun nuage de point généré.") + "\n" + + texte += "\n Taille du chantier : "+str(sizeDirectoryMO(self.repTravail))+" MO" # Affichage : os.chdir(self.repTravail) - self.encadre(texte,nouveauDepart='oui') + self.encadre(texte,nouveauDepart='non') except Exception as e: - texte = "Les caractéristiques du chantier précédent \n"+self.chantier+"\n n'ont pas pu être lues correctement.\n"+\ - "Le fichier des paramètres est probablement incorrect.\n"+\ - "Un nouveau chantier a été ouvert afin de débloquer la situation.\n"+\ - "Désolé pour l'incident.\n\n"+\ - "Erreur : "+str(e) +"\n"+texte - self.initialiseValeursParDefaut() - os.chdir(self.repTravail) - self.encadre(texte,nouveauDepart='oui') - - + texte = _("Les caractéristiques du chantier précédent") + "\n" + self.chantier + "\n" + _("n'ont pas pu être lues correctement." ) + "\n"+\ + _("Le fichier des paramètres est probablement incorrect ou vous avez changé la version de l'interface.") + "\n"+\ + _("Certaines fonctions seront peut_être défaillantes.") + "\n"+\ + _("Désolé pour l'incident.") + "\n\n"+\ + _("Erreur : ")+str(e) +"\n"+texte + self.encadre(texte,nouveauDepart='non') + +############### Existance des maitres 2D 3D : vrai, faux + def existeMasque3D(self): - if self.repTravail==self.repertoireScript: + if self.repTravail==self.repertoireData: return False - self.masque3D = os.path.join(self.repTravail,self.masque3DSansChemin) + self.masque3D = os.path.join(self.repTravail,self.masque3DSansChemin) if os.path.exists(self.masque3D): return True else: return False - def existeMasque2D(self): - if self.repTravail==self.repertoireScript: - return False - if os.path.exists(self.masque) and os.path.exists(self.maitre) and self.modeMalt.get()=="GeomImage": - return True - if str(self.modeMalt.get())=="GeomImage": # pas besoin de masque ! - return False - return True + def existeMaitre2D(self): + if self.repTravail==self.repertoireData: # pas enregistré + return False + if str(self.modeMalt.get())!="GeomImage": # pas besoin d'image maîtresse ! + return True + if self.listeDesMaitresses.__len__()>0: # GeoImage et maitresses : OK + return True + else: # le mode est geomimage et il n'y a pas d'image maitre + return False + +############### Affichages des photos choisies, points, masques, distance... def afficherToutesLesPhotos(self): - self.choisirUnePhoto(self.photosAvecChemin, - titre='Toutes les photos', + if self.photosPourCalibrationIntrinseque.__len__()==0: + titre = _('Toutes les photos') + message = _('Toutes les photos') + else: + titre = _('Toutes les photos utiles') + message = _('Toutes les photos') + '\n' + _('sans les %s photos pour calibration intrinseque') % (str( self.photosPourCalibrationIntrinseque.__len__())) + + self.choisirUnePhoto(self.photosSansChemin, + titre=titre, mode='single', - message="Toutes les photos", - messageBouton="Fermer") + message=message, + messageBouton=_("Fermer")) def afficherLesPointsGPS(self): photosAvecPointsGPS = [ e[1] for e in self.dicoPointsGPSEnPlace.keys() ] # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y if photosAvecPointsGPS.__len__()==0: - self.encadre("Aucun point GPS saisi.") + self.encadre(_("Aucun point GPS saisi."),nouveauDepart='non') return self.choisirUnePhoto(photosAvecPointsGPS, - titre='Affichage des photos avec points GPS', + titre=_('Affichage des photos avec points GPS'), mode='single', - message="seules les photos avec points sont montrées.", - messageBouton="Fermer", + message=_("seules les photos avec points sont montrées."), + messageBouton=_("Fermer"), dicoPoints=self.dicoPointsGPSEnPlace) - def afficherMasqueEtMaitre(self): - if os.path.isfile(self.masque) and os.path.isfile(self.maitre)>0: - masqueEtMaitre = [self.masque,self.maitre] - self.choisirUnePhoto(masqueEtMaitre, - titre="Visualiser l'image maitresse et le masque 2D", + def afficherLesMaitresses(self): + + self.maltApero() # pour abonder la liste des maitressesApero (un peu lourd) + if self.listeDesMaitresses.__len__()+self.listeDesMaitressesApero.__len__()>0: + self.choisirUnePhoto(self.listeDesMaitresses+self.listeDesMasques+self.listeDesMaitressesApero, + titre=_('Liste des images maîtresses et des masques ')+"\n"+_("communs à GeomImage et AperoDedenis"), mode='single', - message="Répertoire : \n"+os.path.dirname(self.maitre), - messageBouton="Fermer") + message=_("Images maîtresses et masques"), + messageBouton=_("Fermer") + ) else: - self.encadre("Pas de masque 2D défini pour ce chantier") + self.encadre(_("Pas de maîtresses définies pour ce chantier"),nouveauDepart='non') + + def afficherMasqueTarama(self): + + if os.path.exists(self.masqueTarama): + self.choisirUnePhoto([self.mosaiqueTaramaJPG,self.masqueTarama], + titre=_('Mosaique Tarama et masque ')+"\n"+_("Option Ortho de Malt"), + mode='single', + message=_("Image maîtresse et masque"), + messageBouton=_("Fermer") + ) + def afficheMasqueC3DC(self): if self.existeMasque3D()==False: - self.encadre("Pas de masque 3D pour ce chantier.") + self.encadre(_("Pas de masque 3D pour ce chantier."),nouveauDepart='non') return os.chdir(self.repTravail) self.topMasque3D = tkinter.Toplevel(relief='sunken') fenetreIcone(self.topMasque3D) self.item900 = ttk.Frame(self.topMasque3D,height=5,relief='sunken',padding="0.3cm") - self.item901 = ttk.Button(self.item900,text='Visaliser le masque 3D',command=self.affiche3DApericloud) + self.item901 = ttk.Button(self.item900,text=_('Visaliser le masque 3D'),command=self.affiche3DApericloud) self.item901.pack(ipady=2,pady=10) - self.item903 = ttk.Button(self.item900,text='Fermer',command=lambda : self.topMasque3D.destroy()) + self.item903 = ttk.Button(self.item900,text=_('Fermer'),command=lambda : self.topMasque3D.destroy()) self.item903.pack(ipady=2,pady=10) - self.item902 = ttk.Label(self.item900, text= "Affichage du masque 3D :\n\n"+\ - "Les points blancs du nuage sont dans le masque\n"+\ - "Ce masque C3DC a la priorité sur le masque 2D de Malt\n\n"+ - "ATTENTION : FERMER la fenêtre 3D pour continuer") - self.item902.pack(ipady=2,pady=10) - - + self.item902 = ttk.Label(self.item900, text=_("Affichage du masque 3D :") + "\n\n"+ + _("Les points blancs du nuage sont dans le masque") + "\n"+ + _("Ce masque C3DC a la priorité sur le masque 2D de Malt") + "\n\n"+ + _("ATTENTION : pour continuer FERMER la fenêtre 3D")+ "\n"+ + _("puis cliquer si besoin sur le bouton FERMER ci-dessus.")) + self.item902.pack(ipady=2,pady=10) self.item900.pack() fenetre.wait_window(self.topMasque3D) def afficherZonePlane(self): if len(self.monImage_MaitrePlan)>0: - masqueEtMaitre = [self.monImage_PlanTif,self.monImage_MaitrePlan] - if self.monImage_PlanTif==self.planProvisoireHorizontal: - plan = "horizontale" - else: - plan = "verticale" - self.choisirUnePhoto(masqueEtMaitre, - titre="Visualiser l'image maitresse et le plan horizontal ou vertical", + if os.path.exists(self.monImage_PlanTif) and os.path.exists(self.monImage_MaitrePlan): + masqueEtMaitre = [self.monImage_PlanTif,self.monImage_MaitrePlan] + if self.monImage_PlanTif==self.planProvisoireHorizontal: + plan = _("horizontale") + else: + plan = _("verticale") + self.choisirUnePhoto(masqueEtMaitre, + titre=_("Visualiser l'image maîtresse et le plan horizontal ou vertical"), mode='single', - message="Zone plane "+plan, - messageBouton="Fermer") + message=_("Zone plane ")+plan, + messageBouton=_("Fermer")) + else: + self.monImage_PlanTif = self.monImage_MaitrePlan = str() + self.encadre("Pas de plan horizontal ou vertical défini pour ce chantier",nouveauDepart='non') else: - self.encadre("Pas de plan horizontal ou vertical défini pour ce chantier") + self.encadre(_("Pas de plan horizontal ou vertical défini pour ce chantier"),nouveauDepart='non') def afficherLigneHV(self): photosAvecLigneH = [ e[1] for e in self.dicoLigneHorizontale.keys() ] @@ -1823,35 +3091,85 @@ def afficherLigneHV(self): sens = str() for e in self.dicoLigneHorizontale: dicoAvecLigne[e] = self.dicoLigneHorizontale[e] - sens = "HORIZONTALE" + sens = _("HORIZONTALE") for e in self.dicoLigneVerticale: dicoAvecLigne[e] = self.dicoLigneVerticale[e] - sens = "VERTICALE" + sens = _("VERTICALE") if photosAvecLigne.__len__(): self.choisirUnePhoto(photosAvecLigne, - titre='Affichage des photos avec ligne horizontale ou verticale', + titre=_('Affichage des photos avec ligne horizontale ou verticale'), mode='single', - message="ligne "+sens, - messageBouton="Fermer", + message=_("ligne ")+sens, + messageBouton=_("Fermer"), dicoPoints=dicoAvecLigne) else: - self.encadre("Pas de ligne horizontale ou verticale définie pour ce chantier") + self.encadre(_("Pas de ligne horizontale ou verticale définie pour ce chantier"),nouveauDepart='non') def afficherDistance(self): - if self.distance.get()==str(): - self.encadre("Pas de distance définie pour ce chantier.") - else: - photosAvecDistance = list(set([ e[1] for e in self.dicoCalibre.keys() ])) - self.choisirUnePhoto(photosAvecDistance, - titre="Visualiser les photos avec distance", - mode='single', - message="Valeur de la distance : "+self.distance.get(), - messageBouton="Fermer", - dicoPoints=self.dicoCalibre) + try: + float(self.distance.get().split(" ")[0]) #pour permettre la saisie d'une unité + except: + self.encadre(_("Pas de distance correcte définie pour ce chantier."),nouveauDepart='non') + return + + photosAvecDistance = list(set([ e[1] for e in self.dicoCalibre.keys() ])) + self.choisirUnePhoto(photosAvecDistance, + titre=_("Visualiser les photos avec distance"), + mode='single', + message=_("Valeur de la distance : ")+self.distance.get(), + messageBouton=_("Fermer"), + dicoPoints=self.dicoCalibre) - def lectureTraceMicMac(self,complete=True): + def afficherCalibIntrinseque(self): + if self.photosPourCalibrationIntrinseque.__len__()==0: + self.encadre(_("Pas de photos pour la calibration intrinsèque par Tapas."),nouveauDepart='non') + return + self.choisirUnePhoto(self.photosPourCalibrationIntrinseque, + titre=_('Les photos pour calibration intrinsèque (Tapas)'), + mode='single', + message=_("Calibration intrinsèque"), + messageBouton=_("Fermer")) + + def afficheMosaiqueTarama(self): + + if not os.path.exists(self.mosaiqueTaramaTIF): + self.encadre(_("Pas de mosaique. Choisir l'option Tarama de tapas."),nouveauDepart='non') + return - if self.pasDePhoto():return + if not os.path.exists(self.mosaiqueTaramaJPG): + self.conversionJPG(liste=[self.mosaiqueTaramaTIF]) + if not os.path.exists(self.mosaiqueTaramaJPG): + self.encadre(_("Echec de la conversion mosaique en JPG."),nouveauDepart='non') + return + + self.choisirUnePhoto([self.mosaiqueTaramaJPG], + titre=_('Mosaique créée par Tarama'), + mode='single', + message="", + messageBouton=_("Fermer")) + + def afficheMosaiqueTawny(self): + orthoMosaiqueTIF = os.path.join(self.repTravail,"Ortho-MEC-Malt",self.orthoMosaiqueTawny) # chemin complet + if not os.path.exists(orthoMosaiqueTIF): + self.encadre(_("Pas d' ortho mosaique par Tawny. Choisir l'option Tawny de Malt."),nouveauDepart='non') + return + orthoMosaiqueJPG = os.path.splitext(orthoMosaiqueTIF)[0]+".JPG" + print("orthoMosaiqueJPG=",orthoMosaiqueJPG) + if not os.path.exists(orthoMosaiqueJPG): + self.conversionJPG(liste=[orthoMosaiqueTIF]) + if not os.path.exists(orthoMosaiqueJPG): + self.encadre(_("Echec de la conversion de la mosaïque TIF en JPG."),nouveauDepart='non') + return + + self.choisirUnePhoto([orthoMosaiqueJPG], + titre=_('Ortho mosaique créée par Tawny'), + mode='single', + message="", + messageBouton=_("Fermer")) + +############### Affichages des traces + + def lectureTraceMicMac(self,complete=True): if complete: fichier = self.TraceMicMacComplete @@ -1860,271 +3178,583 @@ def lectureTraceMicMac(self,complete=True): os.chdir(self.repTravail) if os.path.exists(fichier): self.cadreVide() - trace=open(fichier,"r") - contenu=trace.read() + trace=open(fichier,"r",encoding="utf-8") + try: + contenu=trace.read() + except: # pour compatibilité ascendante + trace.close + trace=open(fichier,"r",encoding="latin-1") + contenu=trace.read() trace.close self.ajoutLigne(contenu) self.texte201.see("1.1") else: - texte = "Pas de trace de la trace !" - self.encadre(texte) + texte = _("Pas de trace de la trace !") + self.encadre(texte,nouveauDepart='non') def lectureTraceSynthetiqueMicMac(self): self.lectureTraceMicMac(complete=False) +############### Affichages des nuages de points + def afficheApericloud(self): retour = self.lanceApericloudMeshlab() if retour == -1: - self.encadre("Pas de nuage de points aprés Tapas.") + self.encadre(_("Pas de nuage de points aprés Tapas."),nouveauDepart='non') if retour == -2: - self.encadre("Programme pour ouvrir les .PLY non trouvéé.") + self.encadre(_("Programme pour ouvrir les .PLY non trouvéé."),nouveauDepart='non') def affiche3DNuage(self): - retour = self.lanceMeshlab() + retour = self.ouvreModele3D() if retour == -1 : - self.encadre("Pas de nuage de points aprés Malt ou C3DC.") + self.encadre(_("Pas de nuage de points aprés Malt ou C3DC."),nouveauDepart='non') if retour == -2 : - self.encadre("Programme pour ouvrir les .PLY non trouvé.") + self.encadre(_("Programme pour ouvrir les .PLY non trouvé."),nouveauDepart='non') ################################## Le menu PARAMETRAGE : répertoires MicMAc et Meshlab ########################################################### def afficheParam(self): - texte =('\nRépertoire bin de MicMac : \n\n'+afficheChemin(self.micMac)+ - '\n\n------------------------------\n'+ - '\n\nOutil exiftool : \n\n'+afficheChemin(self.exiftool)+ - '\n\n------------------------------\n'+ - '\n\nOutil pour afficher les .ply : \n\n'+afficheChemin(self.meshlab)+ - '\n\n------------------------------\n') - self.encadre(texte) + texte =('\n' + _("Répertoire bin de MicMac : ")+'\n\n'+afficheChemin(self.micMac)+ + '\n------------------------------\n'+ + '\n' + _("Version MicMac :")+'\n\n' + str(self.mercurialMicMac)+ + '\n------------------------------\n'+ + '\n' + _("Outil exiftool :") + '\n\n' + afficheChemin(self.exiftool)+ + '\n------------------------------\n'+ + '\n' + _("Outil convert d\'ImageMagick :") + ' \n\n' + afficheChemin(self.convertMagick)+ + '\n------------------------------\n'+ + '\n' + _("Outil pour afficher les .ply :") + '\n\n' + afficheChemin(self.meshlab)+ + '\n------------------------------\n'+ + '\n' + _("Outil pour décompacter les vidéos (ffmpeg):") + "\n\n" + afficheChemin(self.ffmpeg)+ + '\n------------------------------\n'+ + '\n' + _("Répertoire d'AperoDeDenis :") + "\n\n" + afficheChemin(self.repertoireScript)+ + '\n------------------------------\n'+ + '\n' + _("Répertoire des paramètres :") + "\n\n" + afficheChemin(self.repertoireData)+ + '\n------------------------------\n') + self.encadre(texte,nouveauDepart='non') def repMicmac(self): - if self.micMac=="": - texte="Pas de chemin pour le répertoire MICMAC\\bin." - else: - texte="Répertoire bin sous MICMAC : "+afficheChemin(self.micMac) + + self.menageEcran() + + #affichage de la valeur actuelle du répertoire de micmpac : + + texte=_("Répertoire bin sous MICMAC : ")+afficheChemin(self.micMac) self.encadre(texte,nouveauDepart='non') # pour éviter le redémarrage de la fenêtre - # Choisir le répertoire de MicMac existe = False - exiftoolOK = False - source=tkinter.filedialog.askdirectory(title='Désigner le répertoire bin sous Micmac ',initialdir=self.micMac) + exiftoolOK = False + convertOK = False + ffmpegOK = False + + # Choisir le répertoire de MicMac + + source=tkinter.filedialog.askdirectory(title=_('Désigner le répertoire bin sous Micmac '),initialdir=self.micMac) + if len(source)==0: - texte="Abandon, pas de changement.\nRépertoire bin de Micmac : \n\n"+afficheChemin(self.micMac) - self.encadre(texte) + texte=_("Abandon, pas de changement.") + "\n" + _("Répertoire bin de Micmac :") + "\n\n"+afficheChemin(self.micMac) + self.encadre(texte,nouveauDepart='non') + return + + if " " in source: + texte = _("Le chemin du répertoire bin de micmac ne doit pas comporter le caractère 'espace'.") + "\n" + texte = _("Renommer le répertoire de MicMac.") + "\n" + texte += _("Abandon, pas de changement.") + "\n" + _("Répertoire bin de Micmac :") + "\n\n"+afficheChemin(self.micMac) + self.encadre(texte,nouveauDepart='non') return + + # mm3d sous Windows : + if self.systeme=="nt": - self.mm3d = os.path.join(source,"mm3d.exe") - if os.path.exists(self.mm3d): + mm3d = os.path.join(source,"mm3d.exe") + + if os.path.exists(mm3d): self.micMac = source + self.mm3d = mm3d existe = True + else: + self.encadre(_("Le répertoire %s ne contient pas le fichier mm3d.exe. Abandon") % (source),nouveauDepart='non') + return + return + + # chemin pour lire les exifs + if self.pasDeExiftool(): + exiftool = os.path.join(source+"aire-aux","exiftool.exe") # recherche de l'existence de exiftool sous binaire-aux + if os.path.exists(exiftool): + self.exiftool = exiftool + exiftoolOK = True + else: + exiftool = os.path.join(source+"aire-aux\\windows","exiftool.exe") # le répertoire change dans les dernières versions de micmac + if os.path.exists(exiftool): + self.exiftool = exiftool + exiftoolOK = True + else: exiftoolOK = True + + # chemin pour convertir les formats de photos + if self.pasDeConvertMagick(): + convertMagick = os.path.join(source+"aire-aux","convert.exe") + if os.path.exists(convertMagick): + self.convertMagick = convertMagick + convertOK = True + else: + convertMagick = os.path.join(source+"aire-aux\\windows","convert.exe") + if os.path.exists(convertMagick): + self.convertMagick = convertMagick + convertOK = True + else: convertOK = True - exiftool = os.path.join(source+"aire-aux","exiftool.exe") # recherche de l'existence de exiftool sous binaire-aux - if os.path.exists(exiftool): - self.exiftool = exiftool - exiftoolOK = True - + # Chemin de ffmpeg pour décompacter les vidéo : si existe + if self.pasDeFfmpeg(): + ffmpeg = os.path.join(source,"ffmpeg.exe") # vrai dans certaines anciennes versions de micmac + if os.path.exists(ffmpeg): + self.ffmpeg = ffmpeg + ffmpgegOK = True + + + # mm3D sous linux, mas os : + if self.systeme=="posix": - self.mm3d = os.path.join(source,"mm3d") - if os.path.exists(self.mm3d): + mm3d = os.path.join(source,"mm3d") + if os.path.exists(mm3d): self.micMac = source + self.mm3d = mm3d existe = True - - '''exiftool = os.path.join(self.micMac+"aire-aux","exiftool") # la recherche d'exitool sous ubuntu ne peut se faire comme cela : on demande à l'utilisateur - if os.path.exists(exiftool): - self.exiftool = exiftool''' + else: + self.encadre(_("Le répertoire %s ne contient pas le fichier mm3d. Abandon") % (source),nouveauDepart='non') + return + + # DicoCamera : self.CameraXML = os.path.join(os.path.dirname(self.micMac),self.dicoCameraGlobalRelatif) + + # Vérification que mm3D fonctionne : + executable = verifierSiExecutable(self.mm3d) if executable: # nouveau répertoire correct self.micMac = source - texte="Nouveau répertoire de Micmac : \n\n"+afficheChemin(self.micMac) + texte=_("Nouveau répertoire de Micmac :") + "\n\n"+afficheChemin(self.micMac) self.sauveParam() else: if existe: - texte = "Le programme mm3d est présent mais ne peut s'exécuter.\n Vérifier si la version est compatible avec le système. :\n" + texte = _("Le programme mm3d est présent mais ne peut s'exécuter.") + "\n" + _("Vérifier si la version est compatible avec le système. :") + "\n" else: - texte = "Le programme mm3d est absent du répertoire choisi :\n"+source+"\n Répertoire bin sous MicMac incorrect. \nAbandon." + texte = _("Le programme mm3d est absent du répertoire choisi :") + "\n"+source+"\n" + _("Répertoire bin sous MicMac incorrect.") +"\n" + _("Abandon.") - if exiftoolOK: - texte = texte + "\n\nChemin de exiftool :\n\n"+self.exiftool + # chemin pour exiftool si sous micmac\bin : - self.mm3dOK = verifMm3d(self.mm3d) # Booléen indiquant si la version de MicMac permet la saisie de masque 3D - self.encadre(texte) + if exiftoolOK: + texte = texte + "\n\n" + _("Chemin de exiftool :") + "\n\n"+self.exiftool + if convertOK: + texte = texte + "\n\n" + _("Chemin de convert d'image Magick :") + "\n\n" +self.convertMagick + if ffmpegOK: + texte = texte + "\n\n" + _("Chemin de ffmpeg :") + "\n\n" +self.ffmpeg + + self.mm3dOK = verifMm3d(self.mm3d) # Booléen indiquant si la version de MicMac permet la saisie de masque 3D + self.mercurialMicMac = mercurialMm3d(self.mm3d) + if self.mercurialMicMac==False: + self.mercurialMicMac = _("Pas de version identifiée de MicMac") + self.ajoutLigne("\n" + _("Nouvelle version de MicMac : ")+str(self.mercurialMicMac)+"\n") + self.ecritureTraceMicMac() + self.encadre(texte,nouveauDepart='non') def repExiftool(self): + self.menageEcran() if self.exiftool=="": - texte="Pas de chemin pour le programme exiftool" + texte=_("Pas de chemin pour le programme exiftool") else: - texte="Programme exiftool :\n"+afficheChemin(self.exiftool) + texte=_("Programme exiftool :") + "\n"+afficheChemin(self.exiftool) self.encadre(texte,nouveauDepart='non') - # Choisir le répertoire de Meshlab ou CLoudCompare : + # Choisir le répertoire de exiftool : + _filetypes = [] if sys.platform == 'darwin' else [("exiftool","exiftool*"),(_("Tous"),"*")] source=tkinter.filedialog.askopenfilename(initialdir=os.path.dirname(self.exiftool), - filetypes=[('exiftool','exiftool.*;*.app'),('tous','.*')],multiple=False, - title = "Recherche exiftool") + filetypes=_filetypes, + multiple=False, + title = _("Recherche exiftool")) if len(source)==0: - texte="Abandon, pas de changement.\nFichier exiftool inchangé :\n\n"+afficheChemin(self.exiftool) - self.encadre(texte) + texte=_("Abandon, pas de changement.") + "\n" + _("Fichier exiftool inchangé :") + "\n\n"+afficheChemin(self.exiftool) + self.encadre(texte,nouveauDepart='non') return self.exiftool=''.join(source) self.sauveParam() - texte="\nProgramme exiftool :\n\n"+afficheChemin(self.exiftool) - self.encadre(texte) + texte="\n" + _("Programme exiftool :") + "\n\n" +afficheChemin(self.exiftool) + self.encadre(texte,nouveauDepart='non') + def repConvert(self): + self.menageEcran() + if self.convertMagick=="": + texte=_("Pas de chemin pour le programme convert d'ImageMagick") + else: + texte=_("Programme convert :") + "\n"+afficheChemin(self.convertMagick) + self.encadre(texte,nouveauDepart='non') + + # Choisir le répertoire de convert d'ImageMagick : + _filetypes = [] if sys.platform == 'darwin' else [("convert",("convert*","avconv*")),(_("Tous"),"*")] + source=tkinter.filedialog.askopenfilename(initialdir=os.path.dirname(self.exiftool), + filetypes=_filetypes, + multiple=False, + title = _("Recherche convert")) + if len(source)==0: + texte=_("Abandon, pas de changement.") + "\n" + _("Fichier convert inchangé :") + "\n\n"+afficheChemin(self.convertMagick) + self.encadre(texte,nouveauDepart='non') + return + self.convertMagick=''.join(source) + self.sauveParam() + texte="\n" + _("Programme convert :") + "\n\n"+afficheChemin(self.convertMagick) + self.encadre(texte,nouveauDepart='non') + def repMeslab(self): + self.menageEcran() if self.meshlab=="": - texte="Pas de chemin pour le programme ouvrant les .PLY" + texte=_("Pas de chemin pour le programme ouvrant les .PLY") else: - texte="Programme ouvrant les .PLY :\n"+afficheChemin(self.meshlab) + texte=_("Programme ouvrant les .PLY :") + "\n"+afficheChemin(self.meshlab) self.encadre(texte,nouveauDepart='non') - # Choisir le répertoire de Meshlab ou CLoudCompare : + # Choisir le répertoire de Meshlab ou CLoudCompare + _filetypes = [] if sys.platform == 'darwin' else [(_("meshlab ou CloudCompare"),("meshlab*","Cloud*")),(_("Tous"),"*")] source=tkinter.filedialog.askopenfilename(initialdir=os.path.dirname(self.meshlab), - filetypes=[('meshlab ou cloud compare','meshlab.*;*.app;cloud*;*'),('tous','.*')],multiple=False, - title = "Recherche fichier Meshlab sous VCG, ou CloudCompare") + filetypes=_filetypes, + multiple=False, + title = _("Recherche fichier Meshlab sous VCG, ou CloudCompare")) + if len(source)==0: + texte=_("Abandon, pas de changement.") + "\n" + _("Fichier Meshlab ou cloud compare :") + "\n\n"+afficheChemin(self.meshlab) + self.encadre(texte,nouveauDepart='non') + return + self.meshlab = source + self.sauveParam() + texte="\n" + _("Programme ouvrant les .PLY :") + "\n\n"+afficheChemin(self.meshlab) + self.encadre(texte,nouveauDepart='non') + + def repFfmpeg(self): + self.menageEcran() + if self.ffmpeg=="": + texte=_("Pas de chemin pour le programme Ffmpeg") + else: + texte=_("Programme ffmpeg :") + "\n"+afficheChemin(self.ffmpeg) + self.encadre(texte,nouveauDepart='non') + + # Choisir le répertoire de ffmpeg: + _filetypes = [] if sys.platform == 'darwin' else [("ffmpeg","ffmpeg*"),(_("Tous"),"*")] + source=tkinter.filedialog.askopenfilename(initialdir=os.path.dirname(self.ffmpeg), + filetypes=_filetypes, + multiple=False, + title = _("Recherche ffmpeg")) if len(source)==0: - texte="Abandon, pas de changement.\nFichier Meshlab ou cloud compare :\n\n"+afficheChemin(self.meshlab) - self.encadre(texte) + texte=_("Abandon, pas de changement.") + "\n" + _("Fichier ffmpeg inchangé :") + "\n\n"+afficheChemin(self.ffmpeg) + self.encadre(texte,nouveauDepart='non') return - self.meshlab=''.join(source) + self.ffmpeg=''.join(source) self.sauveParam() - texte="\nProgramme ouvrant les .PLY :\n\n"+afficheChemin(self.meshlab) - self.encadre(texte) + texte="\n" + _("Programme ffmpeg :") + "\n\n"+afficheChemin(self.ffmpeg) + self.encadre(texte,nouveauDepart='non') + + def modifierTacky(self): + self.tacky = not self.tacky + if self.tacky: + self.encadre(_("Tacky message au lancement activé")) + else: + self.encadre(_("Tacky message au lancement désactivé")) + + def modifierLangue(self): + self.menageEcran() + self.encadre(_("Sélectionnez la langue à utiliser. L'application sera redémarrée.")) + frame = tkinter.Frame(fenetre) + frameListe = tkinter.Frame(frame) + frameBoutton = tkinter.Frame(frame) + self.choixLangue = tkinter.Listbox(frameListe) + frame.pack() + frameListe.pack(side = tkinter.TOP) + frameBoutton.pack(side = tkinter.BOTTOM) + valider = tkinter.Button(frameBoutton, text = _("Appliquer"), command = self.selectionLangue) + self.choixLangue.pack(side = tkinter.LEFT, fill = tkinter.Y) + valider.pack() + self.choixLangue.insert(1, _("Français")) + self.choixLangue.insert(2, _("Anglais")) + + def selectionLangue(self): + nouvelleLangue = self.choixLangue.get(self.choixLangue.curselection()) + global langue + if(nouvelleLangue == _("Français")): + langue = 'fr' + else: + langue = 'en' + try: + traduction = gettext.translation('AperoDeDenis', localedir = repertoire_langue, languages=[langue]) + traduction.install() + except: + message = "Version bilingue non installée. Revoir la procédure d'installation.\nChoisir KO pour quitter l'application" + if self.troisBoutons(titre="traduction absente",question=message,b1='OK',b2='KO',b3=None,b4=None)==1: + self.quitter() + try: fenetre.destroy() + except: pass ################################## LE MENU MICMAC : Choisir les photos, les options, le traitement ########################################################## def lesPhotos(self): # Choisir des images dans un répertoire - self.fermerVisuPhoto() # s'il y a une visualisation en cours des photos ou du masque on la ferme + if not os.path.isdir(self.micMac): + self.encadre(_("Avant de choisir les photos associer le répertoire bin de micmac (Menu Paramétrage\\associer le répertoire bin de MicMac)."),nouveauDepart='non') + return + + if not os.path.isfile(self.exiftool): + self.encadre(_("Avant de choisir les photos associer le chemin du programme exiftool (Menu trage\\Associer exiftool)."),nouveauDepart='non') + return + self.fermerVisuPhoto() # s'il y a une visualisation en cours des photos ou du masque on la ferme + self.menageEcran() + reinitialationAFaire = False if self.etatDuChantier>2: # 1 = avec photo ; 2 = enregistré, plus = traitement effectué - if self.deuxBoutons("Réinialiser le chantier.", - "Les résultats en cours seront effacés.\n Pour conserver le chantier créer un nouveau chantier.?", - "Abandon", - "Réinitialiser") == 0: + reinitialationAFaire = True + if self.troisBoutons(_("Nouvelles photos pour le meme chantier"), + _("Choisir de nouvelles photos réinitialisera le chantier." ) + "\n"+ + _("Les traces et l'arborescence des calculs seront effacées.") + "\n"+ + _("Les options compatibles avec les nouvelles photos seront conservées.") + "\n", + _("Abandon"), + _("Réinitialiser le chantier")) == 0: + self.encadre(_("Abandon, le chantier n'est pas modifié."),nouveauDepart='non') return - - - photos=tkinter.filedialog.askopenfilename(title='Choisir des JPEG', - initialdir=self.repertoireDesPhotos, - filetypes=[('Photos JPG',('*.JPG')),('tous','*.*')], + + + repIni = "" # répertoire initial de la boite de dialogue + if os.path.isdir(self.repertoireDesPhotos): + repIni = self.repertoireDesPhotos + + photos=tkinter.filedialog.askopenfilename(title=_('Choisir des photos'), + initialdir=repIni, + filetypes=[(_("Photos"),("*.JPG","*.jpg","*.BMP","*.bmp","*.TIF","*.tif")),(_("Tous"),"*")], multiple=True) if len(photos)==0: - self.encadre("Abandon, aucune sélection,\n le répertoire et les photos restent inchangés.\n") + self.encadre(_("Abandon, aucune sélection de fichier image,") + "\n" + _("le répertoire et les photos restent inchangés.") + "\n",nouveauDepart="non") return if self.nombreDExtensionDifferentes(photos)==0: - self.encadre("Aucune extension acceptable pour des images. Abandon.") + self.encadre(_("Aucune extension acceptable pour des images. Abandon."),nouveauDepart="non") return if self.nombreDExtensionDifferentes(photos)>1: - self.encadre("Plusieurs extensions différentes :\n"+",".join(self.lesExtensions)+".\n Impossible dans cette version. Abandon.") + self.encadre(_("Plusieurs extensions différentes :") + "\n"+",".join(self.lesExtensions)+".\n" + _("Impossible dans cette version. Abandon."),nouveauDepart="non") return - if self.lesExtensions[0] not in ".JPG.JPEG": - self.encadre("La version actuelle ne traite que les photos au format JPG, or le format des photos est "+self.lesExtensions[0]+". Désolé." ) - return + if self.lesExtensions[0].upper() not in ".JPG.JPEG": + + if self.troisBoutons(_("Info : format des photos"),_("La version actuelle ne traite que les photos au format JPG,") + "\n\n" + _("or le format des photos est : ")+self.lesExtensions[0]+ + ".\n\n" + _("les photos vont être converties au format JPG."), + b1=_('Convertir en JPG'), + b2=_('Abandonner'))==1: + return + if verifierSiExecutable(self.convertMagick)==False: + self.encadre(_("Désigner l'outil de conversation 'convert' d'ImageMagick") + "\n" + _("(Menu Paramétrage)"),nouveauDepart="non") + return + if self.pasDeConvertMagick():return + + self.conversionJPG(photos) + photos = [os.path.splitext(e)[0]+".JPG" for e in photos] + + if self.nombreDExtensionDifferentes(photos)==0: + self.encadre(_("Aucune extension acceptable pour des images. Abandon."),nouveauDepart="non") + return + + + # si des points GPS placés sur d'anciennes photos : vont-ils être supprimés ? + + NbPointsSupprimes = int() + if self.dicoPointsGPSEnPlace.__len__()>0: + photosAvecPointsGPS = set([os.path.basename(e[1]) for e in self.dicoPointsGPSEnPlace.keys()]) + photosChoisies = [os.path.basename(e) for e in photos] + for e in photosAvecPointsGPS: + if e not in photosChoisies: + NbPointsSupprimes+=1 # le compte n'y est pas (si positif) + if NbPointsSupprimes>0: + if self.troisBoutons(_("ATTENTION !"),_("ATTENTION : des points GPS ont été précedemment placés sur des photos non choisies pour ce chantier.") + "\n"+ + _("Les emplacements de ces points vont être supprimés si vous validez cette sélection de photos."), + b1=_('Valider la sélection de photos'), + b2=_('Abandonner'))==1: + return + + + # Nouvelle sélection valide self.extensionChoisie = self.lesExtensions[0] # l'extension est OK - - self.encadre("Copie des photos en cours... Patience",nouveauDepart='non') # pour éviter le redémarage + + self.encadre(_("Copie des photos en cours... Patience"),nouveauDepart='non') # pour éviter le redémarage + + # crée le repertoire de travail, copie les photos avec l'extension choisie et renvoit le nombre de fichiers photos "aceptables", + # met à 1 l'état du chantier crée self.photosAvecChemin et self.photosSansChemin + # ATTENTION : Supprime l'arborescence et certains résultats. - retourExtraire=self.extrairePhotoEtCopier(photos) # crée le repertoire de travail, copie les photos et renvoit le nombre de fichiers photos "aceptables" + retourExtraire = self.extrairePhotoEtCopier(photos) if retourExtraire.__class__()=='': # si le retour est un texte alors erreur, probablement création du répertoire impossible - self.encadre (retourExtraire) + self.encadre (_("Impossible de créer le répertoire de travail.") + "\n" + _("Vérifier les droits en écriture sous le répertoire des photos") + "\n"+str(retourExtraire),nouveauDepart="non") return if retourExtraire==0: # extraction et positionne self.repertoireDesPhotos, et les listes de photos avec et sanschemin (photosAvecChemin et photosSansChemin) - self.encadre ("Aucun JPG sélectionné,\nle répertoire et les photos restent inchangés.\n") + self.encadre (_("Aucun JPG, PNG, BMP, TIF, ou GIF sélectionné,") + "\n" + _("le répertoire et les photos restent inchangés.") + "\n",nouveauDepart="non") return - # conséquences du choix de nouvelles photos : on supprime tous le répertoire de travail ancien - # - même si la photo maitre n'est pas choisie on supprime le maitre et le masque - # - s'il y a une visualisation en cours des photos ou du masque on la ferme + self.etatSauvegarde="*" # chantier modifié + + # Controle des photos : + - self.masque = str() # nom du fichier image représentant le masque sur l'image maitresse - self.masqueSansChemin = str() # image masque : en TIF, choisi par l'utilisateur - self.maitreSansChemin = str() # image maitresse - self.maitreCommentaire = str() # indique si l'image maitresse est choisie automatiquement - self.maitre = str() - self.fichierMasqueXML = str() # nom du fichier XML décrivant le masque - self.nomMaitreSansExtension = str() + self.controlePhotos() # Vérifie l'exif et les dimensions des photos + message = str() + if self.exifsOK==False: + if self.pasDeFocales: + if self.pasDeExiftool(): + message+=_("L'outil exiftool n'est pas localisé : controle des photos impossible.") + "\n" + _("Désigner le fichier exiftool (menu paramétrage).") + else: + message+=_('Les focales sont absentes des exif.') + "\n" + _('Mettez à jour les exifs avant de lancer MicMac.') + '\n'+\ + _("Utiliser le menu Outils/Modifier l'exif des photos.") + "\n" + else: + message += _("Attention : Les focales des photos ou ne sont pas toutes identiques.") + "\n" + + if self.dimensionsOK==False: + message += _("Attention : les dimensions des photos ne sont pas toutes identiques.") + "\n"+\ + "\n" + _("Le traitement par MicMac ne sera peut-être pas possible.") + "\n" + + # conséquences du choix de nouvelles photos sur un ancien chantier : on supprime tous le répertoire de travail ancien + # on conserve les options + # - s'il y a une visualisation en cours des photos ou du masque on la ferme + + + self.reinitialiseMaitreEtMasqueDisparus() #fait un grand ménage + self.photosPourCalibrationIntrinseque = [e for e in self.photosPourCalibrationIntrinseque if e in photos] + + if reinitialationAFaire: + # trace dans la trace + message = (_("De nouvelles photos ont été sélectionnés sur un chantier pré-existant.") + "\n"+ + _("Les anciennes options compatibles avec les nouvelles photos ont été conservées.") + "\n") + + self.ajoutLigne(message) + self.ecritureTraceMicMac() + + + # sauvegarde = recréation du fichier param.sav qui a été supprimé + + self.enregistreChantier() + + # affiche etat avec message : + + self.afficheEtat(message) - self.etatSauvegarde="*" # chantier modifié - self.afficheEtat() - # extraire les photos dans le résultat de l'opendialogfilename (celui-ci dépend de l'OS et du nombre 0,1 ou plus de fichier choisis) : # puis création du chantier (si impossible : erreur ! ################################## COPIER LES FICHIERS DANS LE REPERTOIRE DE TRAVAIL ########################################################### + ################################## ATTENTION : FAIT UN GRAND MENAGE : supprime toute l'arborescence de travail et des fichiers dans le chantier dont param.sav ############### - def extrairePhotoEtCopier(self,photos): # création repertoire du chantier, copie les photos OK, chdir. retour : nombre de photos - # photosPropresAvecChemin photosAvecChemin photosSansChemin - liste=[x for x in photos if x[-3:].upper() in 'JPGJPEG'] # on restreint aux deux formats d'images identifiés correct / JPG + def extrairePhotoEtCopier(self,photos): # création repertoire du chantier, copie les photos OK, chdir. retour : nombre de photos ou message d'erreur + # photosAvecChemin photosSansChemin + #attention : self.extensionChoisie doit être positionné - if len(liste)==0: - return 0 - liste.sort() - oldRepertoireDesphotos = self.repertoireDesPhotos - self.repertoireDesPhotos=os.path.dirname(liste[0]) # si positif alors on affecte le repertoire (string) - self.photosAvecChemin= list(liste) # les photos avec les chemins initiaux - - # création du répertoire du chantier si nouveau chantier - - if self.etatDuChantier==0 or oldRepertoireDesphotos!=self.repertoireDesPhotos: # nouveau répertoire si pas de photos ou changement de répertoire # si pas encore de nom pour le chantier on lui en donne un ! - retour = self.creationNouveauRepertoireTravail() - if isinstance(retour, str): - return retour #y a un pb + liste=[x for x in photos if x[-3:].upper() in 'JPGJPEGPNGRAWBMPTIFTIFFGIF'] # on restreint aux seul format d'images accepté : JPG, PNG, BMP, TIF, RAW, GIF + if len(liste)==0: return 0 + + # Quel répertoire pour le chantier ? + retour = self.quelChantier(liste[0]) + + if retour!=None: + return retour # y a un pb - # copie des photos sous le répertoire de travail : (attention, il peut y en avoir d'autres, qui seront supprimées au lancement de Micmac, mais pas de la qualité) - - listeCopie=list() # liste des fichiers copiés, vide + # copie des photos sous le répertoire de travail : (attention, il peut y en avoir d'autres, + # qui seront supprimées au lancement de Micmac, mais pas de la qualité) + liste.sort() + self.photosAvecChemin = list(liste) # les photos avec les chemins initiaux, triées alphabétique + listeCopie=list() # liste des fichiers copiés, vide try: - for e in self.photosAvecChemin: # self.photosPropresAvecChemin est la liste des photos nettoyées à copier - if self.extensionChoisie.upper() in e.upper(): # ON NE COPIE QUE L'EXTENSION CHOISIE, en majuscule - dest=os.path.join(self.repTravail,os.path.basename(e).upper().replace(" ","_")) #sans blanc : mm3d plante ! + self.extensionChoisie = self.extensionChoisie.upper() + for f in self.photosAvecChemin: # self.photosAvecChemin est la liste des photos nettoyées à copier + self.encadrePlus("...") + if self.extensionChoisie in f.upper(): # ON NE COPIE QUE L'EXTENSION CHOISIE, en majuscule + dest=os.path.join(self.repTravail,os.path.basename(f).upper().replace(" ","_")) # en majuscule et sans blanc : mm3d plante ! if not os.path.exists(dest): # on ne copie que si le fichier n'est pas déjà présent - shutil.copy(e,dest) # copie du fichier sous le répertoire de travail - ajout(listeCopie,dest) # liste des fichiers à traiter - except Exception as err: - texte= 'erreur lors de la copie du fichier\n'+e+'\n dans le répertoire \n'+self.repTravail+"\nlibellé de l'erreur : \n"+str(err)+\ - "\nCauses possibles : manque d'espace disque ou droits insuffisants." + shutil.copy(f,dest) # copie du fichier sous le répertoire de travail + ajout(listeCopie,dest) # liste des fichiers à traiter + except Exception as e: + texte= _("erreur lors de la copie du fichier") + "\n" + f + "\n" + _("dans le répertoire ") + "\n" + self.repTravail + "\n" + _("libellé de l\'erreur :") + "\n" + str(e) + "\n" + _("Causes possibles : manque d\'espace disque ou droits insuffisants.") return texte - - self.photosPropresAvecChemin = list(listeCopie) # listes des photos copiées - self.photosSansChemin=list([os.path.basename(x) for x in listeCopie]) # liste des noms de photos copiès, sans le chemin. [tuple] - - supprimeArborescenceSauf(self.repTravail,self.photosSansChemin) # suppression de tous sous le répertoire actuel : sauf photos sélectionnées, (résultats, traces, arbres) - + self.photosAvecChemin = list(listeCopie) # on oublie les photos initiales + self.photosSansChemin = list([os.path.basename(x) for x in listeCopie]) # liste des noms de photos copiès, sans le chemin. + # on conserve les options déjà saisies, mais pas les résultats de traitement qui n'ont plus de sens + # suppression de tous sous le répertoire actuel : sauf photos sélectionnées et paramètres saisis + aConserver = list(self.photosSansChemin) + aConserver += [e for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".xml"] # garde les xml (paramètres) + aConserver += [e for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".exp"] # garde les exports + aConserver += [e for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".ply"] # garde les ply + aConserver += [e for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".txt"] # garde les traces + aConserver.append(self.monImage_PlanTif) + aConserver += self.listeDesMasques + supprimeArborescenceSauf(self.repTravail,aConserver) os.chdir(self.repTravail) - self.etatDuChantier = 1 # les photos sont choisies, le répertoire de travail est créé - - # définit les fichiers trace vides, débuter la trace - - self.definirFichiersTrace() # positionne sous le répertoire de travail + self.etatDuChantier = 1 # les photos sont choisies, le répertoire de travail est créé + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + # définit les fichiers trace vides, débuter la trace à vide (tout nouveau choix de photos efface la trace précédente + self.typeDuChantier = ['photos','initial','original'] + self.definirFichiersTrace() # affecte leur noms auc fichiers trace, existant ou pas, sous le répertoire de travail + self.initialisationFichiersTrace() # Efface les anciens et initialisation de nouveaux fichiers trace + return len(listeCopie) # on retourne le nombre de photos + + ################# controler les photos dans leur ensemble : même focale, mêmes dimensions, présence d'un exif avec focale : + + def controlePhotos(self): #[liste = self.photosSansChemin] Vérification globale des focales et des dimensions. + # le nombre : au moins 2 + if self.photosSansChemin.__len__()<=1: + self.assezDePhotos = False + else: self.assezDePhotos = True + # les dimensions : + + self.dimensionsDesPhotos = [(x,Image.open(x).size) for x in self.photosSansChemin] # si OK : x = self.dimensionsDesPhotos[0][0] et y=self.densionsDesPhotos[0][1] + self.dimensionsOK = set([y for (x,y) in self.dimensionsDesPhotos]).__len__()==1 # vrai si une seule taille + # les focales : + if set([x for x in self.photosSansChemin])!=set([x[0] for x in self.exifsDesPhotos]): # car cette procédure est longue !!! + self.exifsDesPhotos = [(x,self.tagExif(tag="FocalLength",photo=x)) for x in self.photosSansChemin] + lesFocales = set([y for (x,y) in self.exifsDesPhotos]) + self.exifsOK = False + self.pasDeFocales = False + try: + if '' in lesFocales: + self.pasDeFocales = True + if lesFocales.__len__()==1 and self.pasDeFocales==False: + self.exifsOK = True + except Exception as e: print(_("erreur controle des photos : "),str(e)) + + ################# définir le répertoire de travail, le créer : + + def quelChantier(self,unePhoto): # on a une photo ou une vidéo : quel répertoire de travail et quel chantier ? - open(self.TraceMicMacSynthese,'w').close() # création d'un fichier de trace, vide - open(self.TraceMicMacComplete,'w').close() # création d'un fichier de trace, vide + self.chantier = os.path.basename(self.repTravail) # par défaut on suppose que le répertoire existe déjà : on ne change rien - self.ajoutLigne(heure()+ "\n\nChoix des photos :\n"+"\n".join(self.photosAvecChemin)+"\n") - self.ajoutLigne(heure()+ "\n\nrépertoire du chantier :\n"+self.repTravail+"\n\n") - self.ecritureTraceMicMac() + # Le répertoire de unePhoto est-il le répertoire des photos : si oui on ne change pas le répertoire de travail, sinon nouveau $repTravail et nouveau chantier + + oldRepertoireDesphotos = self.repertoireDesPhotos - return len(listeCopie) # on retourne le nombre de fichi + self.repertoireDesPhotos = os.path.normcase(os.path.dirname(unePhoto)) # si positif alors on affecte le repertoire (string) + + # création du répertoire du chantier si nouveau chantier + # état du chantier : 1 = créé, fixé ; si 0 : alors il faut créer un nouveau chantier + if self.etatDuChantier==0 or oldRepertoireDesphotos!=self.repertoireDesPhotos: # nouveau répertoire si pas de photos ou changement de répertoire # si pas encore de nom pour le chantier on lui en donne un ! + return self.creationNouveauRepertoireTravail() # si pas de changement de répertoire des photos alors pas de création def creationNouveauRepertoireTravail(self): - self.indiceTravail+=1 - self.repTravail=os.path.join(self.repertoireDesPhotos,'MicMac_'+str(self.indiceTravail)) + # Numéro du chantier : pour indicer le numéro du répertoire de travail : un nouveau est créé à chaque éxécution + + try: self.indiceTravail += 1 # on incrémente s'il existe + except: self.indiceTravail = 1 # sinon met à 1 sinon + + self.repTravail = os.path.normcase(os.path.normpath(os.path.join(self.repertoireDesPhotos,'MicMac_'+str(self.indiceTravail)))) while os.path.exists(self.repTravail): # détermine le nom du répertoire de travail (chantier) self.indiceTravail+=1 # numéro particulier au répertoire de travail créé - self.repTravail=os.path.join(self.repertoireDesPhotos,'MicMac_'+str(self.indiceTravail))# répertoire différent à chaque éxécution (N° séquentiel) + self.repTravail = os.path.normcase(os.path.normpath(os.path.join(self.repertoireDesPhotos,'MicMac_'+str(self.indiceTravail)))) # répertoire différent à chaque éxécution (N° séquentiel) try: os.mkdir(self.repTravail) # création répertoire du chantier - except Exception as e : return "Impossible de créer le répertoire de travail : erreur = \n"+str(e) + except Exception as e : return _("Impossible de créer le répertoire de travail : erreur = ") + "\n"+str(e) ajout(self.tousLesChantiers,self.repTravail) # on ajoute le répertoire créé dans la liste des répertoires self.chantier = os.path.basename(self.repTravail) # nom du chantier, puis état du chantier : 1 = créé, fixé @@ -2138,14 +3768,38 @@ def optionsOnglet(self): # l'état du chantier permet-il de choisir des options : if self.etatDuChantier==3: - self.encadre("Le chantier est interrompu suite à incident. \n\n"+ - "Si besoin créer un nouveau chantier ou débloquer le chantier en lancant micmac.") + self.encadre(_("Le chantier est interrompu suite à incident. ") + "\n\n"+ + _("Si besoin créer un nouveau chantier ou débloquer le chantier en lancant micmac."),nouveauDepart='non') return - if self.etatDuChantier==5: - self.encadre("Le chantier est terminé. Modification des options inutile.\n\n."+ - "Si besoin créer un nouveau chantier ou débloquer le chantier en lancant micmac.") - return + # Chantier arrété après tapas : l'utilisateur a pu modifier les options et veut continuer ou reprendre au début suivant les résultats + # poursuite du traitement ou arrêt suivant demande utilisateur + + + # Chantier terminé, l'utilisateur peur décider de le débloquer en conservant les résultats de tapas ou supprimer tous les résultats + + if self.etatDuChantier==5: # Chantier terminé + retour = self.troisBoutons( titre=_('Le chantier %(x)s est terminé.') % {"x" : self.chantier}, + question=_("Le chantier est terminé après ")+self.densification+".\n"+ + _("Vous pouvez :") + "\n"+ + _(" - Nettoyer le chantier pour modifier les options de Tapioca et Tapas") + "\n"+ + _(" - Conserver les traitements de Tapioca/Tapas pour modifier les options de Malt ou C3DC") + "\n"+ + _(" - Ne rien faire.") + "\n", + b1=_('Modifier les options de Tapioca et Tapas'), + b2=_('Modifier les options de Malt ou C3DC'), + b3=_('Ne rien faire'),) + if retour==-1: # -1 : fermeture fenêtre, abandon + self.afficheEtat() + return + if retour==2: # 0 : ne rien faire (b3)) + self.afficheEtat() + return + if retour==0: # 1 : on nettoie, on passe à l'état 2 (b1)) + self.nettoyerChantier() + + if retour==1: # modifier les options de malt C3DC et points GPS (b2)) + self.etatDuChantier = 4 + # L'état du chantier permet de choisir des options : @@ -2159,66 +3813,90 @@ def optionsOnglet(self): self.onglets.add(self.item500) # tapas self.onglets.add(self.item950) # Calibration self.optionsTapioca() # les frames à afficher ne sont pas "fixes" - self.item510.pack() # la frame fixe de tapas - self.item710.pack(pady=15) # Malt + self.item520.pack(pady=10) # la frame fixe de tapas pour calibration + self.item510.pack(pady=10) # la frame fixe de tapas pour arrêt ou poursuite + self.item540.pack(pady=10) # la frame fixe de tapas pour arrêt ou poursuite + self.item526.config(text=_("Nombre de photos choisies : ")+str(self.photosPourCalibrationIntrinseque.__len__())) + self.item720.pack(pady=10) # Malt + self.optionsMalt() # La frame Image Maitre à afficher n'est pas "fixe" self.item960.pack(padx=5,pady=10,ipady=2,ipadx=15) # Calibration de 960 à 980 self.item965.pack() # calibration suite self.item970.pack(padx=5,pady=10,ipady=2,ipadx=15) # calibration suite self.item975.pack() # calibration suite self.item980.pack(padx=5,pady=10,ipady=2,ipadx=15) # calibration suite - self.item990.pack() # calibration suite + self.item990.pack() # calibration suite selection = self.item400 # onglet sélectionné par défaut else: self.onglets.hide(self.item400) # tapioca self.onglets.hide(self.item500) # tapas self.onglets.hide(self.item950) # Calibration - self.item710.pack(pady=15) # Malt : toujours présent + self.item720.pack(pady=10) # Malt + self.optionsMalt() # La frame Image Maitre à afficher n'est pas "fixe" selection = self.item700 - - if self.mm3dOK: # ne pas proposer C3DC si MicMac ne l'accepte pas + #Onglet C3DC : + + if not self.mm3dOK: # ne pas proposer C3DC si MicMac ne l'accepte pas os.chdir(self.repTravail) - supprimeFichier(self.masque3DSansChemin) # suppression des anciens masques 3D - supprimeFichier(self.masque3DBisSansChemin) - else: + if os.path.exists(self.masque3DSansChemin): + supprimeFichier(self.masque3DSansChemin) # suppression des anciens masques 3D + supprimeFichier(self.masque3DBisSansChemin) + self.ajoutLigne(_("Suppression du masque 3D : la version de MicMac ne comporte pas C3DC")) + self.ecritureTraceMicMac() try: self.onglets.hide(self.item800) except: pass + + else: #Si l'onglet existe on met à jour les messages : + + os.chdir(self.repTravail) + if os.path.exists("AperiCloud.ply")==False: + self.item804.configure(text= _("pas de fichier AperiCloud.ply pour construire le masque :") + "\n" + _("lancer Micmac pour en constituer un."),foreground='red',style="C.TButton") + self.item801.configure(state = "disable") + else: + self.item801.configure(state = "normal") + if self.existeMasque3D(): + self.item804.configure(text = _("Masque 3D créé"),foreground='black') + else: + self.item804.configure(text = _("Pas de masque 3D"),foreground='black') + + # met à jour les infos sur les maîtresses et les masques + + self.miseAJourItem701_703() + self.masqueProvisoire = str() # utile pour tracemasque + # dernier onglet (qui se régénére, forcément le dernier) self.optionsReperes() # points GPS, en nombre variable # points de repères calés dans la scène self.onglets.pack(fill='none', padx=2, pady=0) # on active la boite à onglet self.item450.pack() # et les 2 boutons en bas - self.onglets.select(selection) # onglet sélectionné par défaut - + self.onglets.select(selection) # onglet sélectionné par défaut + fenetre.wait_window(self.onglets) # boucle d'attente : la fenêtre pricncipale attend la fin de l'onglet def finOptionsOK(self): # l'utilisateur a valider l'ensemble des options + self.onglets.pack_forget() # on ferme la boite à onglets texte = str() - # Pour Tapioca : toutes les variables sont sauvées - # Pour tapas : - - self.maitreSansChemin = os.path.basename(self.maitre) # photoMaitre sans chemin avec extension, en minuscule - - self.ecrireMasqueXML() # création du fichier xml associé à l'image maitresse - - try: del self.masqueRetour # suppression de l'objet "saisie du masque" s'il existe - except : pass # on enregistre les options de calibration et de GPS self.finCalibrationGPSOK() # mise à jour des options de calibration self.finRepereOK() # mise à jour des options de repérage (axe Ox, plan horizontal, distance - # Sauvegarde des nouvelles info : + # Controle puis Sauvegarde des nouvelles info : + + retour = self.controleOptions() - self.sauveParam() self.etatSauvegarde="*" # chantier modifié ="*" #Pour indiquer que le chantier a été modifié, sans être sauvegardé sous le répertoire du chantier - - if self.controleOptions()!=True: # Controle de cohérence de la saisie (valeur entière...) - texte=("Saisie d'une option incomplète ou incorrecte.\nCorriger.\n"+str(self.controleOptions())) + self.sauveParam() + + if retour!=True: + texte = "\n" + _("Option incorrecte :") + "\n"+str(retour) + self.encadreEtTrace(texte) + return + self.afficheEtat(texte) def finCalibrationGPSOK(self): # crée le fichier xml qui va bien avec les données saisies @@ -2226,19 +3904,20 @@ def finCalibrationGPSOK(self): # crée le fichi supprimeFichier(self.mesureAppuis) self.actualiseListePointsGPS() # met a jour proprement la liste des 6-tuples (nom,x,y,z,actif,identifiantgps) if self.dicoPointsGPSEnPlace.__len__()==0: # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y - return - if self.controlePoints(): - self.encadre("Points GPS non conformes. Vérifiez.",nouveauDepart='non') - return + return False + if self.controlePointsGPS()==False: # retour False si problème ! + self.encadre(_("Points GPS non conformes. Nom est absent ou en double. Vérifiez."),nouveauDepart='non') + return False + os.chdir(self.repTravail) - with open(self.dicoAppuis, 'w', encoding='utf-8') as infile: #écriture de la description de chaque point GPS + with open(self.dicoAppuis, 'w', encoding='utf-8') as infile: # écriture de la description de chaque point GPS infile.write(self.dicoAppuisDebut) - self.actualiseListePointsGPS() - for Nom,X,Y,Z,num,ident in self.listePointsGPS: # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) - point=self.dicoAppuis1Point.replace("Nom",Nom) + for Nom,X,Y,Z,num,ident,incertitude in self.listePointsGPS: # listePointsGPS : 7-tuples (nom du point, x, y et z gps, booléen actif, identifiant) + point=self.dicoAppuis1Point.replace(_("Nom"),Nom) point=point.replace("X",X) point=point.replace("Y",Y) - point=point.replace("Z",Z) + point=point.replace("Z",Z) + point=point.replace("10 10 10",incertitude) infile.write(point) infile.write(self.dicoAppuisFin) @@ -2253,40 +3932,88 @@ def finCalibrationGPSOK(self): # crée le fichi if key!="": infile.write(self.mesureAppuisFinPhoto) key = cle[1] - photo = self.mesureAppuisDebutPhoto.replace("NomPhoto",os.path.basename(cle[1])) + photo = self.mesureAppuisDebutPhoto.replace(_("NomPhoto"),os.path.basename(cle[1])) infile.write(photo) - point = self.mesureAppuis1Point.replace("NomPoint",cle[0]) + point = self.mesureAppuis1Point.replace(_("NomPoint"),cle[0]) point = point.replace("X",self.dicoPointsGPSEnPlace[cle][0].__str__()) point = point.replace("Y",self.dicoPointsGPSEnPlace[cle][1].__str__()) - infile.write(point) + if cle[0] not in self.pointsPlacesUneFois: # on n'écrit pas le point s'il n'est présent que sur une seule photo + infile.write(point) else: - point = self.mesureAppuis1Point.replace("NomPoint",cle[0]) + point = self.mesureAppuis1Point.replace(_("NomPoint"),cle[0]) point = point.replace("X",self.dicoPointsGPSEnPlace[cle][0].__str__()) point = point.replace("Y",self.dicoPointsGPSEnPlace[cle][1].__str__()) - infile.write(point) + if cle[0] not in self.pointsPlacesUneFois: # on n'écrit pas le point s'il n'est présent que sur une seule photo + infile.write(point) infile.write(self.mesureAppuisFinPhoto) infile.write(self.mesureAppuisFin) - - def controlePointsGPS(self): # controle pour affiche etat : informer de la situation : si vrai alors self.etatPointsGPS sera affiché - #si pas de chantier, pas de problème mais retour False : pas de calibration + return True + + def controlePointsGPS(self): # controle pour affiche etat et afficher tous les points : informer de la situation : + # le message self.etatPointsGPS sera affiché dans l'état du chantier + # finCalibrationGPSOK doit avoir été éxécuté avant self.etatPointsGPS = str() - if self.repTravail==self.repertoireScript: + retour = True + + if self.repTravail==self.repertoireData: # si pas de chantier, pas de problème mais retour False : pas de calibration return False - listePointsActifs = [ (e[0],e[5]) for e in self.listePointsGPS if e[4] and e[0]!="" ] # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) - if len(listePointsActifs)>0: - self.etatPointsGPS = ("\n"+str(len(self.dicoPointsGPSEnPlace))+" points GPS placés\n"+ # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y - "pour "+str(len(listePointsActifs))+" points GPS définis\n") - return True - - if os.path.exists(os.path.join(self.repTravail,self.mesureAppuis))==False: - self.etatPointsGPS+="Saisie incomplète : les points ne seront pas pris en compte\n" + # listePointsGPS : liste de (nom du point, x, y et z gps, booléen actif, identifiant, incertitude) + listePointsActifs = [f[0] for f in self.listePointsGPS if f[4] and f[0]!=""] + + # ICI : on pourrait controler que les x,y,z et incertitudes sont bien des valeurs numériques + if len(listePointsActifs)==0: + self.etatPointsGPS += _("Pas de points GPS.") + "\n" return False - def controleCalibration(self): # controle de saisie globale du repère, arrêt à la première erreur, True si pas d'erreur, sinon message + if listePointsActifs: + # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + self.etatPointsGPS = ("\n" + _("%s points GPS placés") % (str(len(self.dicoPointsGPSEnPlace))) + "\n" + + _("pour %s points GPS définis") % (str(len(listePointsActifs)))) + "\n" + if len(listePointsActifs)<3: + self.etatPointsGPS += _("Attention : il faut au moins 3 points pour qu'ils soient pris en compte.") + "\n" + retour = False + + # sur le modèle pythonique l'élément le plus représenté dans une liste l : x=sorted(set(l),key=l.count)[-1] + # ou pour avoir toute l'info [(valeur,nombre),...] : [(e,a.count(e)) for e in a] + # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + # ce bout de code est dupliqué dans controlePointsGPS et actualiseListePointsGPS + + listePointsPlaces=[e[0] for e in self.dicoPointsGPSEnPlace] + pointsPlaces = [(e,listePointsPlaces.count(e)) for e in listePointsPlaces] + self.pointsPlacesUneFois = [f[0] for f,g in set([(e,pointsPlaces.count(e)) for e in pointsPlaces]) if g==1] + self.pointsPlacesUneFois.sort() + + # Nombre de points placés 2 fois ou plus : + self.pointsPlacesDeuxFoisOuPlus = [f[0] for f,g in set([(e,pointsPlaces.count(e)) for e in pointsPlaces]) if g>1] + + ############################################ + + if self.pointsPlacesDeuxFoisOuPlus.__len__()<3: + self.etatPointsGPS += _("Il n'y a pas 3 points placés sur 2 photos : les points GPS seront ignorés.")+"\n" + retour = False + if self.pointsPlacesUneFois.__len__()>1: + self.etatPointsGPS += _("Anomalie : les points suivants ne sont placés que sur une seule photo : ")+"\n"+\ + " ".join(self.pointsPlacesUneFois)+"\n" + if self.pointsPlacesUneFois.__len__()==1: + self.etatPointsGPS += _("Anomalie : le point suivant n'est placé que sur une seule photo : ")+"\n"+\ + " ".join(self.pointsPlacesUneFois)+"\n" + + # vérification : y-a-t-il 2 points avec les mêmes coordonnées géographiques ? + + xyz = [(f[1],f[2],f[3]) for f in self.listePointsGPS if f[4] and f[0]!=""] + if xyz.__len__()!=set(xyz).__len__(): + self.etatPointsGPS+=_("Attention : plusieurs points GPS ont les mêmes coordonnées.") + "\n" + + if retour==False: + self.etatPointsGPS+=_("Saisie incomplète : les points GPS ne seront pas pris en compte") + "\n" + + return retour + + def controleCalibration(self): # controle de saisie globale du repère axe, plan métrique, arrêt à la première erreur, True si pas d'erreur, sinon message #si pas de chantier, pas de problème mais retour False : pas de calibration self.etatCalibration = str() - if self.repTravail==self.repertoireScript: + if self.repTravail==self.repertoireData: return False # fichier xml présent : @@ -2294,25 +4021,38 @@ def controleCalibration(self): # controle de saisie globale du return False #ligne : if len(self.dicoLigneHorizontale)+len(self.dicoLigneVerticale)!=2: - self.etatCalibration = self.etatCalibration+"La ligne horizontale ou verticale ne comporte pas 2 points\n" - # Plan : - if os.path.exists(self.monImage_PlanTif)==False: - self.etatCalibration = self.etatCalibration+"Pas de plan horizontal ou vertical\n" + self.etatCalibration = self.etatCalibration+_("La ligne horizontale ou verticale ne comporte pas 2 points") + "\n" + # Plan : + if os.path.exists(self.monImage_MaitrePlan)==False or self.monImage_MaitrePlan==str(): + self.etatCalibration = self.etatCalibration+_("Pas de maitre plan horizontal ou vertical") + "\n" + self.monImage_PlanTif = str() # réinit le plan sans maitre + else: + if os.path.exists(self.monImage_PlanTif)==False: + self.etatCalibration = self.etatCalibration+_("Pas de plan horizontal ou vertical") + "\n" # Distance - try: - d = float(self.distance.get()) + try : + d=float(self.distance.get().split(" ")[0]) # pour permettre la saisie d'une unité if d<0: - self.etatCalibration = self.etatCalibration+"Distance "+self.distance.get()+" invalide.\n" + self.etatCalibration = _("%(x)s Distance %(y)s invalide.") % {"x": self.etatCalibration, "y": self.distance.get()} + "\n" if d==0: - self.etatCalibration = "Calibration annulée.\n" + self.etatCalibration = _("Calibration annulée.") + "\n" except: - self.etatCalibration = self.etatCalibration+"Pas de distance.\n" + self.etatCalibration = _("%s Pas de distance.") % (self.etatCalibration) + "\n" return False - # métrique : - liste = list(self.dicoCalibre.items()) - if liste.__len__()!=4: - self.etatCalibration = self.etatCalibration+"La distance n'est pas mesurée par 2 points repérés sur 2 photos.\n" - + # métrique : + if self.dicoCalibre.__len__()>0: + liste = list(self.dicoCalibre.items()) + if liste.__len__()!=4: + self.etatCalibration += _("La distance n'est pas mesurée par 2 points repérés sur 2 photos.") + "\n" + photosAvecDistance = list(set([os.path.basename(e[1]) for e in self.dicoCalibre.keys() ])) + if not os.path.exists(photosAvecDistance[0]): + self.etatCalibration += _("La photo avec distance %s est absente.") % (photoavecDistance[0]) + "\n" + if photosAvecDistance.__len__()>1: + if not os.path.exists(photosAvecDistance[1]): + self.etatCalibration += _("La photo avec distance %s est absente.") % (photosAvecDistance[1]) + "\n" + if self.dicoCalibre.__len__()==0: + self.etatCalibration += _("Pas de distance pour la calibration.") + "\n" + if self.etatCalibration==str(): return True # calibration OK, tout va bien else: return False @@ -2322,9 +4062,13 @@ def finRepereOK(self): # ne mettre à jour que pour les var existe = False # par défaut : pas de xml, true si il existe une des variables "reperes" xml = self.miseAEchelleXml + # remplace la virgule possible dans self.distance par un point : + + self.distance.set(self.distance.get().replace(",",".")) # on remplace la virgule éventuelle par un point + # Pattern des fichiers à traiter : - xml = xml.replace("Fichiers",str(' .*'+self.extensionChoisie)) + xml = xml.replace(_("Fichiers"),str(' .*'+self.extensionChoisie)) # axe horizontal, dans le dico : self.dicoLigneHorizontale. key = nom point, photo, identifiant ;Retrouver nom de la photo, coordonnées des points # items = liste de tuple (key,values) soit tuple = (point,photo, id),(x1,y1) @@ -2344,8 +4088,8 @@ def finRepereOK(self): # ne mettre à jour que pour les var xml = xml.replace("photoHorizon",os.path.basename(liste[0][0][1])) xml = xml.replace("X1H",liste[0][1][0].__str__()) - xml = xml.replace("X2H",liste[0][1][1].__str__()) - xml = xml.replace("Y1H",liste[1][1][0].__str__()) + xml = xml.replace("Y1H",liste[0][1][1].__str__()) + xml = xml.replace("X2H",liste[1][1][0].__str__()) xml = xml.replace("Y2H",liste[1][1][1].__str__()) # calibre pour les mesures @@ -2372,119 +4116,198 @@ def finRepereOK(self): # ne mettre à jour que pour les var xml = xml.replace("X2P2",liste[3][1][0].__str__()) xml = xml.replace("Y2P2",liste[3][1][1].__str__()) - xml = xml.replace("distance",self.distance.get()) + xml = xml.replace("distance",self.distance.get().split(" ")[0]) # pour permettre la saisie d'une unité + + # le plan horizontal ou vertical (OK même si absent) + + self.monImage_PlanTif = str() + if os.path.exists(self.planProvisoireHorizontal): + self.monImage_PlanTif = self.planProvisoireHorizontal + existe=True + + if os.path.exists(self.planProvisoireVertical): + self.monImage_PlanTif = self.planProvisoireVertical + existe=True + + xml = xml.replace("monImage_MaitrePlan",os.path.basename(self.monImage_MaitrePlan)) # Nom de l'image maîtresse du plan repere (sans extension) + xml = xml.replace("monImage_Plan",os.path.basename(self.monImage_PlanTif)) # nom du masque correspondant + + if existe: + with open(self.miseAEchelle, 'w', encoding='utf-8') as infile: + infile.write(xml) + with open("MiseAEchelleInitial", 'w', encoding='utf-8') as infile: + infile.write(self.miseAEchelleXml) + else: + supprimeFichier(self.miseAEchelle) + + def controleOptions(self): # controle que les valeurs numériques echelle1, echelle2 et delta sont bien : + # des nombres entiers positif sauf échelle2qui peut = -1 + # et que echelle1 < echelle2 + # et enfin que echelle 1 et 2 sont au max = taille la plus grande de l'image + # ce controle peut-être appelé avant de lancer micMac + # Retour : true si Ok, message d'erreur sinon (string) pas d'avertissement sans conséquence. + texte = str() # message informatif (pas toujours !) + erreur = str() # message erreur + + # remarque la fonction int(str) nécessite que la chaîne représente un nombre entier et non décimal + + # Controle echelle 1 pour le mode All de tapioca + + try: + if self.modeTapioca.get()=="All": + echelle1 = int(self.echelle1.get()) # si erreur saisie (texte!) alors valeur par défaut + except: + echelle1 = 1000 + self.echelle1.set(str(echelle1)) + erreur += "\n" + _("L'échelle pour le mode All de Tapioca est invalide, une valeur par défaut, %s, est affectée.") % (self.echelle1.get()) + "\n" + + try: + if echelle1<50 and echelle1!=-1 and self.modeTapioca.get()=="All": + texte += "\n" + _("Echelle pour le mode All de Tapioca trop petite :") + "\n" + self.echelle1.get() + "\n" + _("Minimum = 50") + "\n" + except: + pass + + # Controle echelle 2 pour le mode MulScale de tapioca (première échelle du MulScale) + + try: + if self.modeTapioca.get()=="MulScale": + echelle2 = int(self.echelle2.get()) + except: + echelle2 = 300 + self.echelle2.set(str(echelle2)) + erreur += "\n" + _("L'échelle 1 pour MulScale de Tapioca est invalide, une valeur par défaut, %s, est affectée.") % (self.echelle2.get()) + "\n" + + try: + if echelle2==-1 and self.modeTapioca.get()=="MulScale": + texte += "\n" + _("L'échelle 1 de MulScale ne doit pas être -1.") + "\n" + _("Elle est mise à 300.") + "\n" + echelle2 = 300 + self.echelle2.set(str(echelle2)) + except: pass + + try: + if echelle2<50 and echelle2!=-1 and self.modeTapioca.get()=="MulScale": + texte += "\n" + _("L'échelle 1 pour le mode MulScale de Tapioca est trop petite : ") + "\n" + self.echelle2.get() + "\n" + _("Minimum = 50, maximum conseillé : 300") + "\n" + except: + pass + + # Controle echelle 3 pour le mode MulScale de tapioca (seconde échelle du MulScale) + + try: + if self.modeTapioca.get()=="MulScale": + echelle3 = int(self.echelle3.get()) + except: + echelle3 = 1200 + self.echelle3.set(str(echelle3)) + erreur += "\n" + _("L'échelle 2 pour le mode MulScale de Tapioca est invalide, une valeur par défaut, %s, est affectée.") % (self.echelle3.get()) + "\n" + + try: + if echelle3<50 and echelle3!=-1 and self.modeTapioca.get()=="MulScale": + texte += "\n" + _("L'échelle 2 pour le mode MulScale de Tapioca est trop petite :") + "\n" + self.echelle3.get() + "\n" + _("Minimum = 50") + "\n" + except: + pass + + # controle cohérence echelle2 et echelle3 + + try: + if echelle3<=echelle2 and echelle3!=-1 and self.modeTapioca.get()=="MulScale": + texte += "\n" + _("L'échelle 2 de MulScale pour tapioca") + "\n" + self.echelle3.get() + "\n" + _("plus petite que l'échelle 1 :") + "\n" + self.echelle2.get() + "\n" + except: + pass + + # Controle échelle pour le mode line - # le plan horizontal ou vertical (OK même si absent) + try: + if self.modeTapioca.get()=="Line": + echelle4 = int(self.echelle4.get()) + except: + echelle4 = 1200 + self.echelle4.set(str(echelle4)) + erreur += "\n" + _("L'échelle pour le mode Line de tapioca est invalide, une valeur par défaut, %s, est affectée.") % (self.echelle4.get()) + "\n" - self.monImage_PlanTif = str() - if os.path.exists(self.planProvisoireHorizontal): - self.monImage_PlanTif = self.planProvisoireHorizontal - existe=True - - if os.path.exists(self.planProvisoireVertical): - self.monImage_PlanTif = self.planProvisoireVertical - existe=True - - xml = xml.replace("monImage_MaitrePlan",os.path.basename(self.monImage_MaitrePlan)) # Nom de l'image maitresse du plan repere (sans extension) - xml = xml.replace("monImage_Plan",os.path.basename(self.monImage_PlanTif)) # nom du masque correspondant + try: + if echelle4<50 and echelle4!=-1 and self.modeTapioca.get()=="Line": + texte += "\n" + _("Echelle pour le mode Line de tapioca trop petite : ") + "\n" + self.echelle4.get() + "\n" % (self.echelle4.get()) + except: + pass + + # Controle delta pour le mode line - if existe: - with open(self.miseAEchelle, 'w', encoding='utf-8') as infile: - infile.write(xml) - with open("MiseAEchelleInitial", 'w', encoding='utf-8') as infile: - infile.write(self.miseAEchelleXml) - else: - supprimeFichier(self.miseAEchelle) + try: + if self.modeTapioca.get()=="Line": + delta = int(self.delta.get()) + except: + delta = 4 + self.delta.set(str(delta)) + erreur += "\n" + _("La valeur de delta pour le mode Line de Tapioca est invalide,") + "\n" + _("une valeur par défaut, %s, est affectée.") % self.delta.get() + "\n" - def controleOptions(self): # controle que les valeurs numériques echelle1, echelle2 et delta sont bien : - # des nombres entiers positif sauf échelle2qui peut = -1 - # et que echelle1 < echelle2 - # et enfin que echelle 1 et 2 sont au max = taille la plus grande de l'image - # ce controle peut-être appelé avant de lancer micMac - texte=str() - echelle1 = int(self.echelle1.get()) - echelle2 = int(self.echelle2.get()) - echelle3 = int(self.echelle3.get()) - echelle4 = int(self.echelle4.get()) - delta = int(self.delta.get()) - if self.modeTapioca.get()=='MulScale': - try: - if 0<=echelle1<50: - texte="\nEchelle 1 trop petite : \n"+self.echelle1.get()+"\nMinimum = 50" - return texte - except: - texte = texte+"\nEchelle non numérique poutr Tapioca : \n"+self.echelle1.get()+"\n" - return texte - try: + try: + if delta<1 and self.modeTapioca.get()=="Line": + texte += "\n" + _("Delta trop petit :") + "\n" + self.delta.get() + "\n" + _("Minimum = 1") + "\n" + except: + pass - if echelle2!=-1: - if echelle30: + if os.path.exists(self.photosAvecChemin[0])==False: + texte += _("La photo %s n'existe plus.") % (self.photosAvecChemin[0]) + return texte+erreur + photo1 = Image.open(self.photosAvecChemin[0]) + largeur,hauteur = photo1.size + del photo1 + inutile = _("Inutile et ralenti le traitement. Modifier.") + maxi = max(largeur,hauteur) + if self.modeTapioca.get()=='All': + if int(self.echelle1.get())>maxi: + texte += "\n" + _("L'échelle pour le mode All de tapioca = ") + self.echelle1.get() + "\n" + _(", est plus grande que la dimension maxi de la photo : ") + "\n" + str(maxi) + "." + "\n\n" + inutile + + if self.modeTapioca.get()=='MulScale': + if int(self.echelle2.get())>maxi: + texte += "\n" + _("L'échelle 2 pour le mode MulScale de tapioca= ") + self.echelle2.get() + "\n" + _("est plus grande que la dimension maxi de la photo :") + "\n" + str(maxi) + "." + "\n\n" + inutile + + if self.modeTapioca.get()=='Line': + if int(self.echelle4.get())>maxi: + texte += "\n" + _("L'échelle pour le mode Line de tapioca = ") + self.echelle2.get() + "\n" + _("est plus grande que la dimension maxi de la photo :") + "\n" + str(maxi) + "." + "\n\n" + inutile + + # retour True ou String + + if texte+erreur==str(): return True - if os.path.exists(self.photosAvecChemin[0])==False: - texte = "La photo "+self.photosAvecChemin[0]+" n'existe plus." - return texte - - photo1 = Image.open(self.photosAvecChemin[0]) - largeur,hauteur = photo1.size - del photo1 - - maxi = max(largeur,hauteur) - if self.modeTapioca.get()=='All': - if int(self.echelle1.get())>maxi: - texte = "\nechelle1 = "+self.echelle1.get()+"\n plus grand que la dimension maxi de la photo : \n"+str(maxi)+".\n\nInutile et ralenti le traitement. Modifier." - return texte - if self.modeTapioca.get()=='MulScale': - if int(self.echelle2.get())>maxi: - texte = "\nechelle2 = "+self.echelle2.get()+"\n plus grand que la dimension maxi de la photo : \n"+str(maxi)+".\n\nInutile et ralenti le traitement. Modifier." - return texte - - return True + else: + return texte+erreur - def finOptionsKO(self): + def finOptionsKO(self): + + self.onglets.pack_forget() # on ferme la boite à onglets self.restaureParamChantier(self.fichierParamChantierEnCours) - self.afficheEtat('Pas de changement.') + self.afficheEtat() #""""""""""""""""""""""" Options de TAPIOCA def optionsTapioca(self): # utilisé dans la syntaxe : Tapioca Line Files Size delta ArgOpt= (ce qui exclut implicitement la syntaxe multiscale) - self.item460.pack_forget() self.item470.pack_forget() self.item480.pack_forget() @@ -2497,104 +4320,321 @@ def optionsTapioca(self): # utilisé dans la syntaxe : Tapio if self.modeTapioca.get()=='Line': self.item470.pack(pady=15) + + #"""""""""""""""""""""""" Options de Malt + + def imagesCalibrationIntrinseques(self): + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return + bulles = dict([(e,"") for e in self.photosPourCalibrationIntrinseque]) + self.choisirUnePhoto(self.photosAvecChemin, + _("Pour calibrer l'appareil photo"), + _("Quelques photos, convergentes, d'angles écartés") + "\n" + _("en jaune la calibration actuelle"), + boutonDeux=_("Supprimer"), + bulles=bulles) + if self.fermerVisu: # sortie par second bouton + self.item526.config(text=_("Pas de photos de calibration intrinseque.")) + self.photosPourCalibrationIntrinseque = list() + return + if self.selectionPhotosAvecChemin.__len__()==0: #sortie par fermeture fenêtre + self.item526.config(text=_("Choix inchangé.") + "\n") + return + self.photosPourCalibrationIntrinseque = self.selectionPhotosAvecChemin + self.item526.config(text=_("Nombre de photos choisies : ")+str(self.selectionPhotosAvecChemin.__len__())) + + #"""""""""""""""""""""""" Options de Malt + + def optionsMalt(self): + self.item710.pack_forget() + self.item730.pack_forget() + self.item740.pack_forget() + self.item745.pack_forget() + self.item750.pack_forget() + if self.modeMalt.get()=='GeomImage': + self.item710.pack(pady=10) + self.item730.pack(pady=10) + if self.modeMalt.get()=='Ortho': + self.item745.pack(pady=5) + self.item740.pack(pady=5) + if self.modeMalt.get()=='AperoDeDenis': + self.item750.pack(pady=5) + self.maltApero() # met à jour la liste des maitresses Apero : self.listeDesMaitressesApero et la liste des tuples + self.miseAJourItem701_703() + + def imageMaitresse(self): # bouton "choisir les maitresses" de l'option GeomImage + if self.photosAvecChemin.__len__()==0: + self.infoBulle("Choisir d'abord les photos du chantier.") + return + + # préparation des infos bulles + + bulles = dict() + + for f in self.listeDesMaitresses: + for e in self.listeDesMasques: + if os.path.splitext(f)[0]+"_masque.tif"==e: + bulles[f]=_("Image maitresse avec masque") + if f not in bulles: + bulles[f]="" # image maitresse sans masque + + # suppression des fichiers masques pour malt ;; ces fichiers sont créés au lancement de Malt + # par contre on garde les dessins des masques (_masque.tif) qui ne seront utiles qui si le nom est dans la liste des masques + + for e in self.photosAvecChemin: + supprimeFichier(os.path.splitext(e)[0]+"_Masq.xml") + supprimeFichier(os.path.splitext(e)[0]+"_Masq.tif") + + # choix des nouvelles maîtresses : + + self.choisirUnePhoto(self.photosAvecChemin, + _("Choisir les maîtresses"), + _("Choisir une ou plusieurs image(s) maîtresse(s)") + "\n" + _("en jaune : les maitresses actuelles") + "\n" + _("Une info bulle informe de la présence d'un masque"), + boutonDeux=_("Supprimer les images maîtresses"), # self.fermerVisu=True + mode="extended", + bulles=bulles) + + # suppression de toutes les maitresses + if self.fermerVisu: # sortie par bouton deux = fermeture de fenêtre + self.fermerVisu=True + self.reinitialiseMaitreEtMasque() + return + #abandon de la saisie + if self.selectionPhotosAvecChemin.__len__()==0: #sortie par fermeture fenêtre ou sans choix + self.item701.config(text=_("Abandon. Choix inchangé.") + "\n") + return + + # nouvelle liste des maitresses : mettre à jour la nouvelle liste des masques + self.listeDesMaitresses = self.selectionPhotosAvecChemin + # mise à jour de la liste des masques : suppression des masques qui ne sont plus dans la liste des maitresses + new = list() + for e in self.listeDesMaitresses: + if ' '.join(self.listeDesMasques).count(os.path.splitext(e)[0]): # la maitresse est dans la liste des masques + nouveauMasque = os.path.splitext(e)[0]+"_masque.tif" + if nouveauMasque in self.listeDesMasques: + new.append(nouveauMasque) + + self.listeDesMasques = list(new) # nouvelle liste des masques + self.miseAJourItem701_703() + + def miseAJourItem701_703(self): # et 745 Onglet Malt, Cadres geomImage et Ortho et AperodeDenis + try: + if self.listeDesMaitresses.__len__()==0: + self.item701.config(text=_("Image maitresse obligatoire pour GeomImage.")) + if self.listeDesMaitressesApero.__len__()==0: + self.item751.config(text=_("Exécuter Tapioca/Tapas pour saisir des masques avec cette option.")) + self.item753.config(state=DISABLED) + else: + self.item753.config(state=NORMAL) + + if self.listeDesMaitresses.__len__()==1: + self.item701.config(text=_("image maîtresse = ")+os.path.basename(self.listeDesMaitresses[0])) + + if self.listeDesMaitressesApero.__len__()==1: + self.item751.config(text=_("image maîtresse = ")+os.path.basename(self.listeDesMaitressesApero[0])) + + + if self.listeDesMaitresses.__len__()>1: + self.item701.config(text=str(self.listeDesMaitresses.__len__())+_(" images maîtresses")) + + if self.listeDesMaitressesApero.__len__()>1: + self.item751.config(text=str(self.listeDesMaitressesApero.__len__())+_(" images maîtresses")) + + if self.listeDesMasques.__len__()==0: + self.item703.config(text="\n" + _("Pas de masque.")) + self.item752.config(text="\n" + _("Pas de masque.")) + + if self.listeDesMasques.__len__()==1: + self.item703.config(text="\n" + _("un seul masque : ")+os.path.basename(self.listeDesMasques[0])) + self.item752.config(text="\n" + _("un seul masque : ")+os.path.basename(self.listeDesMasques[0])) + + if self.listeDesMasques.__len__()>1: + self.item703.config(text="\n"+str(self.listeDesMasques.__len__())+_(" masques")) + self.item752.config(text="\n"+str(self.listeDesMasques.__len__())+_(" masques")) + + if not os.path.exists(self.mosaiqueTaramaTIF): + self.item745.config(text="\n" + _("Pas de mosaique Tarama : pas de masque.")) + self.item745.config(state=DISABLED) + elif os.path.exists(self.masqueTarama): + self.item745.config(text=_("Tracer un nouveau masque sur la mosaique Tarama")) + self.item745.config(state=NORMAL) + else: + self.item745.config(text=_("Tracer un masque sur la mosaique Tarama")) + self.item745.config(state=NORMAL) + except Exception as e: + print(_("erreur dans miseAJour701_703 : "),str(e)) + + def tracerLesMasques(self): # Bouton de l'option GeomImage + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return + self.fermerVisuPhoto() + + if self.listeDesMaitresses.__len__()==0: + self.item703.config(text=_("Il faut au moins une image maîtresse pour définir un masque."), + background="#ffffaa") + return + bulles=dict() + for e in self.listeDesMasques: + for f in self.listeDesMaitresses: + if os.path.splitext(f)[0]+"_masque.tif"==e: + bulles[f]=_("Un masque existe déjà") + self.choisirUnePhoto(self.listeDesMaitresses, + _("Choisir l'image pour le masque"), + _("Choisir une image maîtresse pour le masque\nen jaune = un masque existe"), + mode="single", + bulles=bulles) + + if self.selectionPhotosAvecChemin.__len__()==0: + return + maitre = self.selectionPhotosAvecChemin[0] + masqueEnAttente = os.path.splitext(maitre)[0]+"_masque.tif" + + # l'utilisateur trace le masque - def imageMaitresse(self): - self.choisirUnePhoto(self.photosPropresAvecChemin, - "Choisir l'image maitresse", - "Choisir l'image maitresse pour Malt", - boutonDeux="Supprimer l'image maitresse", - mode="single") - if self.fermerVisu: #sortie par second bouton - self.item701.config(text="Pas d'image maîtresse.") - self.item703.config(text="Pas de masque.") - self.maitre = str() - self.maitreSansChemin = str() - self.masque = "" - self.masqueSansChemin = "" + self.masqueRetour = TracePolygone(fenetre,maitre,masqueEnAttente) # L'utilisateur peut tracer le masque sur l'image maitre + if self.masqueRetour.polygone == True: + ajout(self.listeDesMasques,masqueEnAttente) + self.miseAJourItem701_703() + + def tracerLesMasquesApero(self): # bouton pour l'option de malt aperodedenis + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) return - if self.selectionPhotosAvecChemin.__len__()==0: #sortie par fermeture fenêtre - self.item701.config(text="Abandon. Choix inchangé :\n"+self.maitreSansChemin) - return - self.item703.config(text="pas de masque") # réinitialise le masque - self.masque = "" - self.masqueSansChemin = "" - self.maitreProvisoire = str(self.selectionPhotosAvecChemin[0]) # puis l'image maitresse - self.maitreSansCheminProvisoire=os.path.basename(str(self.selectionPhotosAvecChemin[0])) # photoMaitre sans chemin avec extension, en minuscule - try: shutil.copy(self.maitreProvisoire,self.repTravail) - except: pass - self.maitre = os.path.join(self.repTravail,self.maitreSansCheminProvisoire) - self.item701.config(text="image maitresse = "+self.maitreSansCheminProvisoire) + if os.path.exists(os.path.join(self.repTravail,"Homol"))==False: + self.infoBulle(_("Exécuter d'abord Tapioca/Tapas.")) + return + self.fermerVisuPhoto() + if self.listeDesMaitressesApero.__len__()==0: + self.item751.config(text=_("Pas d'image maîtresse. Bizarre."), + background="#ffffaa") + return + + bulles=dict() + for e in self.listeDesMasques: + for f in self.listeDesMaitressesApero: + if os.path.splitext(f)[0]+"_masque.tif"==e: + bulles[f]=_("Un masque existe déjà") + self.choisirUnePhoto(self.listeDesMaitressesApero, + _("Choisir l'image pour le masque"), + _("Choisir une image maîtresse pour le masque\nen jaune = un masque existe"), + mode="single", + bulles=bulles) + + if self.selectionPhotosAvecChemin.__len__()==0: + return + maitre = self.selectionPhotosAvecChemin[0] + masqueEnAttente = os.path.splitext(maitre)[0]+"_masque.tif" + + # l'utilisateur trace le masque + + self.masqueRetour = TracePolygone(fenetre,maitre,masqueEnAttente) # L'utilisateur peut tracer le masque sur l'image maitre + if self.masqueRetour.polygone == True: + ajout(self.listeDesMasques,masqueEnAttente) + self.miseAJourItem701_703() - def traceMasque(self): + + def traceMasque(self): # Choisir le masque Bouton de l'option GeomImage ou AperoDeDenis self.fermerVisuPhoto() + if self.listeDesMaitresses.__len__()==0: + self.item703.config(text=_("Il faut au moins une image maîtresse pour définir un masque."), + background="#ffffaa") + return + + if self.listeDesMaitresses.__len__()==1: + self.maitre = self.listeDesMaitresses[0] + + # comme il y a plusieurs maîtres possibles il faut choisir ! + else: + self.choisirUnePhoto(self.listeDesMaitresses, + _("Choisir l'image pour le masque"), + _("Choisir une image maîtresse pour le masque"), + mode="single") + if self.selectionPhotosAvecChemin.__len__()==0: + return + else: + self.maitre = self.selectionPhotosAvecChemin[0] + + # un peu brutal si la visu n'est pas celle de la photo maitre, évite les incohérences - if os.path.exists(self.maitre): #l'image maître doit exister + if os.path.exists(self.maitre): # l'image maître doit exister self.masqueProvisoire = os.path.splitext(self.maitre)[0]+"_Masq_provisoire.tif" # Nom du fichier masque, à partir du fichier maître, imposé par micmac - self.masqueSansCheminProvisoire = os.path.basename(self.masqueProvisoire) # sans le chemin + supprimeMasque(self.repTravail,"_Masq.tif") # suppression des anciens masques + supprimeFichier(self.fichierMasqueXML) + self.masquesansChemin = str() self.masqueRetour = TracePolygone(fenetre,self.maitre,self.masqueProvisoire) # L'utilisateur peut tracer le masque sur l'image maitre - if self.masqueRetour.polygone == True: # si retour OK (masqueRetour est un élément de la classe tracePolygone) - self.item703.config(text="masque = "+self.masqueSansCheminProvisoire) # affichage du nom du masque - else: + if self.masqueRetour.polygone == False: # si retour OK (masqueRetour est un élément de la classe tracePolygone) self.masqueProvisoire = str() # pas de masque : détricotage - self.masqueSansCheminProvisoire = str() + self.item703.config(text=_("pas de masque")) else: - self.item703.config(text="Il faut une image maîtresse pour définir un masque.", + self.item703.config(text=_("Il faut une image maîtresse pour définir un masque."), background="#ffffaa") - def ecrireMasqueXML(self): - try: - if self.masqueProvisoire==str(): - return - except: return - self.masque = os.path.splitext(self.maitre)[0]+"_Masq.tif" # nom définitif du masque - self.masqueSansChemin = os.path.basename(self.masque) - if os.path.exists(self.masque): - try: - os.remove(self.masque) - except: - self.encadre ("Impossible de remplacer le fichier masque :\n"+self.masque+"\nVérifier s'il n'est pas ouvert.\n Masque inchangé.", - nouveauDepart='non') - return - os.rename(self.masqueProvisoire,self.masque) # on renomme le fichier (et on écrase l'ancien !) - self.masqueProvisoire = str() # plus de masque provisoire: détricotage - self.masqueSansCheminProvisoire = str() - - self.masqueXML=self.masqueXML.replace("MonImage_Masq.tif",self.masqueSansChemin) #écriture dans le fichier xml - self.masqueXML=self.masqueXML.replace("largeur",str(self.masqueRetour.largeurImageFichier)) - self.masqueXML=self.masqueXML.replace("hauteur",str(self.masqueRetour.hauteurImageFichier)) - self.fichierMasqueXML=self.masque.replace(".tif",".xml") + def MasqueXML(self): # préparation du masque pour malt GeomImage. self.maitreSansChemin est nécessaire + + # le masque est constitué d'un fichier .tif ET d'un fichier .xml (masqueSansChemin est le tif + # la racine des noms est le nom de l'image maître, suivi de _Masq. puis de tif ou xml + + masque = os.path.splitext(self.maitreSansChemin)[0]+"_masque.tif" + + # On vérifie l'existencce du "masque" : + if os.path.exists(masque)==False: + supprimeFichier(self.fichierMasqueXML) # suppression ancien xml + return + # copie du fichier masque tif sous le nom requis par Malt = nom du maitre+"_Masq.tif" + masqueTIF = os.path.splitext(self.maitreSansChemin)[0]+"_Masq.tif" + supprimeFichier(masqueTIF) + shutil.copy(masque,masqueTIF) + + #écriture xml + self.masqueXML = self.masqueXMLOriginal # version initiale du fichier XML + self.masqueXML=self.masqueXML.replace("MonImage_Masq.tif",masqueTIF) # écriture dans le fichier xml + self.masqueXML=self.masqueXML.replace("largeur",str(self.dimensionsDesPhotos[0][1][0])) # x = self.dimensionsDesPhotos[0][0] + self.masqueXML=self.masqueXML.replace("hauteur",str(self.dimensionsDesPhotos[0][1][1])) # y=self.densionsDesPhotos[0][1] + self.fichierMasqueXML=masqueTIF.replace(".tif",".xml") # nom du fichier xml + with open(self.fichierMasqueXML, 'w', encoding='utf-8') as infile: infile.write(self.masqueXML) + def tracerUnMasqueSurMosaiqueTarama(self): + print("self.mosaiqueTaramaTIF=",self.mosaiqueTaramaTIF) + if not os.path.exists(self.mosaiqueTaramaTIF): # en principe existe si on arrive ici + return + print(self.mosaiqueTaramaJPG) + if not os.path.exists(self.mosaiqueTaramaJPG): + self.conversionJPG(liste=[self.mosaiqueTaramaTIF]) + if not os.path.exists(self.mosaiqueTaramaJPG): + print("retour") + return + # l'utilisateur trace le masque + + self.masqueRetour = TracePolygone(fenetre,self.mosaiqueTaramaJPG,self.masqueTarama) # L'utilisateur peut tracer le masque sur l'image maitre + if self.masqueRetour.polygone == True: + self.miseAJourItem701_703() + pass + #""""""""""""""""""""""" Options masque 3D pour C3DC def affiche3DApericloud(self): # lance SAisieMasqQT, sans le fermer.... attente de la fermeture (subprocess.call) - os.chdir(self.repTravail) - if os.path.exists("AperiCloud.ply")==False: - try: - self.item803 = ttk.Label(self.item800, - text= "pas de fichier AperiCloud.ply pour construire le masque :\nlancer Micmac pour en constituer un.", - style="C.TButton") - self.item803.pack(ipady=2,pady=10) - except: pass - return - else: - try: self.item803.destroy() - except: pass masque3D = [self.mm3d,"SaisieMasqQT","AperiCloud.ply"] # " SaisieAppuisInitQT AperiCloud.ply" - self.apericloudExe=subprocess.call(masque3D,shell=self.shell) # Lancement du programme et attente du retour - try: #marche pas si on est en visu + self.apericloudExe = subprocess.call(masque3D,shell=self.shell) # Lancement du programme et attente du retour + + try: # marche pas si on est en visu if self.existeMasque3D(): - self.item803 = ttk.Label(self.item800, text= "masque 3D créé") - self.item803.pack(ipady=2,pady=10) + self.item804.configure(text= _("Masque 3D créé"),foreground='black') else: - self.item803 = ttk.Label(self.item800, text= "Abandon : pas de masque créé.",foreground='red') - self.item803.pack(ipady=2,pady=10) + self.item804.configure(text= _("Abandon : pas de masque créé."),foreground='red') except: pass + + + def supprimeMasque3D(self): + supprimeFichier(self.masque3DSansChemin) # suppression définitive des fichiers pour le masque 3D + supprimeFichier(self.masque3DBisSansChemin) + self.item804.configure(text= _("Masque 3D supprimé."),foreground='red') + #""""""""""""""""""""""" Options de CalibrationGPS : faire correspondre des points (x,y,z) numérotés de 1 à N, avec des pixels des images. @@ -2607,104 +4647,123 @@ def optionsReperes(self): # en entrée : self.listePointsGPS qui comp self.item650 = ttk.Frame( self.onglets, # création du cadre d'accueil de l'onglet height=5, - relief='sunken') + relief='sunken') + # message en haut de fenêtre self.item670 = ttk.Frame(self.item650,height=10,relief='sunken') - self.item671=ttk.Label(self.item670,text="Chaque point doit être placé sur au moins 2 photos",justify='left') - self.item671.pack(pady=10,padx=10,ipady=2,ipadx=2) + texte = _("3 points minimum, chaque point doit être placé sur au moins 2 photos") + "\n\n" + texte+= _("La calibration par points GPS se fait aprés Tapas et avant Malt.") + "\n" + texte+= _("Elle est prioritaire sur la calibration par axe, plan et métrique.") + self.item671=ttk.Label(self.item670,text=texte,justify='left') + self.item671.pack(pady=10,padx=10,ipady=2,ipadx=2,fill="y") self.item670.pack(side='top') - if self.listePointsGPS.__len__()==0: # ajout d'une ligne de saisie blanche si aucun point : - self.listePointsGPS.append(["","","","",True,self.idPointGPS]) # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) - self.idPointGPS += 1 # affichage des entêtes de colonne self.item660 = ttk.Frame(self.item650,height=5,relief='sunken') - self.item661 = ttk.Label(self.item660,text='point').pack(side='left',pady=10,padx=60,fill="both") - self.item662 = ttk.Label(self.item660,text='X').pack(side='left',pady=10,padx=40) - self.item663 = ttk.Label(self.item660,text='Y').pack(side='left',pady=10,padx=70) - self.item664 = ttk.Label(self.item660,text='Z').pack(side='left',pady=10,padx=70) + self.item661 = ttk.Label(self.item660,text='point').pack(side='left',pady=10,padx=40,fill="both") + self.item662 = ttk.Label(self.item660,text='X').pack(side='left',pady=10,padx=60) + self.item663 = ttk.Label(self.item660,text='Y').pack(side='left',pady=10,padx=60) + self.item664 = ttk.Label(self.item660,text='Z').pack(side='left',pady=10,padx=60) + self.item665 = ttk.Label(self.item660,text=_('Incertitude')).pack(side='left',pady=10,padx=30) self.item660.pack(side="top") # préparation des boutons en bas de liste - self.item653=ttk.Button(self.item650,text='Ajouter un point',command=self.ajoutPointCalibrationGPS) - self.item654=ttk.Button(self.item650,text='Supprimer des points',command=self.supprPointsGPS) - self.item655=ttk.Button(self.item650,text='Placer les points',command=self.placerPointsGPS) - + self.item653=ttk.Button(self.item650,text=_('Ajouter un point'),command=self.ajoutPointCalibrationGPS) + self.item654=ttk.Button(self.item650,text=_('Supprimer des points'),command=self.supprPointsGPS) + self.item655=ttk.Button(self.item650,text=_('Placer les points'),command=self.placerPointsGPS) + self.item656=ttk.Button(self.item650,text=_('Appliquer au ') + '\n' + _('nuage non densifié'),command=self.appliquerPointsGPS) + self.item653.pack_forget() #on oublie les boutons du bas s'ils étaient affichés self.item654.pack_forget() self.item655.pack_forget() - + self.item656.pack_forget() # Affichage de la liste des points actuellement saisis: - + self.item680 = ttk.Frame(self.item650,height=10,relief='sunken') self.listeWidgetGPS = list() # liste des widgets affichés, qui sera abondée au fur et à mesure par copie de self.listePointsGPS - for n,x,y,z,actif,ident in self.listePointsGPS: # affichage de tous les widgets nom,x,y,z,actif ou supprimé (booléen), identifiant + self.listePointsGPS.sort(key=lambda e: e[0]) # tri par ordre alpha du nom + + for n,x,y,z,actif,ident,incertitude in self.listePointsGPS: # affichage de tous les widgets nom,x,y,z,actif ou supprimé (booléen), identifiant if actif: # listePointsGPS : liste de tuples (nom du point, x gps, y gps, z gps, booléen actif, identifiant) - self.affichePointCalibrationGPS(n,x,y,z,ident) # ajoute une ligne d'affichage - self.item653.pack(side='left',padx=20) # affichage des boutons en bas d'onglet + self.affichePointCalibrationGPS(n,x,y,z,ident,incertitude) # ajoute une ligne d'affichage + + self.item680.pack() + self.item653.pack(side='left',padx=20) # affichage des boutons en bas d'onglet self.item654.pack(side='left',padx=20) self.item655.pack(side='left',padx=20) + self.item656.pack(side='left',padx=20) - self.onglets.add(self.item650, text="GPS") # affichage onglet - self.onglets.select(self.item650) # active l'onglet + self.onglets.add(self.item650, text="GPS") # affichage onglet - def affichePointCalibrationGPS(self,n,x,y,z,ident): + def affichePointCalibrationGPS(self,n,x,y,z,ident,incertitude): # affiche un point + + f = ttk.Frame(self.item680,height=5,relief='sunken') # cadre d'accueil de la ligne - f = ttk.Frame(self.item650,height=5,relief='sunken') # cadre d'accueil de la ligne self.listeWidgetGPS.append( (f, # cadre : [0] ttk.Entry(f), # zones de saisie de [1] à [4] ttk.Entry(f), ttk.Entry(f), ttk.Entry(f), - ident) - ) - + ident, + ttk.Entry(f) + ) + ) + self.listeWidgetGPS[-1][0].pack(side='top') + if self.onglets.tab(self.onglets.select(), "text")=="GPS" and not self.listeWidgetGPS[-1][0].winfo_viewable(): + self.item650.configure(height=int(self.item650.cget('height'))+2) + #self.onglets.configure(height=int(self.item650.cget('height'))+200) self.listeWidgetGPS[-1][1].pack(side='left',padx=5) self.listeWidgetGPS[-1][1].focus() self.listeWidgetGPS[-1][2].pack(side='left') self.listeWidgetGPS[-1][3].pack(side='left') self.listeWidgetGPS[-1][4].pack(side='left') + self.listeWidgetGPS[-1][6].pack(side='left') self.listeWidgetGPS[-1][1].insert(0,n) # affichage de la valeur dans le widget self.listeWidgetGPS[-1][2].insert(0,x) self.listeWidgetGPS[-1][3].insert(0,y) self.listeWidgetGPS[-1][4].insert(0,z) - + self.listeWidgetGPS[-1][6].insert(0,incertitude) def ajoutPointCalibrationGPS(self): + if self.onglets.tab(self.onglets.select(), "text")=="GPS" and not self.item452.winfo_viewable(): # controle la visibilité des boutons " valider les options" et "annuler" + self.infoBulle(_("Agrandissez la fenêtre avant d'ajouter un point GPS !") + "\n" + _("(ou si impossible : supprimer un point)")) + return self.actualiseListePointsGPS() - if self.listePointsGPS.__len__()>5: - self.infoBulle("Soyez raisonnable : pas plus de 5 points GPS !") + if [ e[0] for e in self.listePointsGPS if e[4]].__len__()>=30: + self.infoBulle(_("Soyez raisonnable : pas plus de 30 points GPS !")) return - - self.listePointsGPS.append(["","","","",True,self.idPointGPS]) # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) + nom = chr(65+self.listePointsGPS.__len__()) + self.listePointsGPS.append([nom,"","","",True,self.idPointGPS,"10 10 10"]) # listePointsGPS : 7-tuples (nom du point, x, y et z gps, booléen actif, identifiant,incertitude) self.idPointGPS += 1 # identifiant du point suivant self.optionsReperes() # affichage avec le nouveau point + self.onglets.select(self.item650) # active l'onglet (il a été supprimé puis recréé par optionsReperes) self.actualiseListePointsGPS() - def supprPointsGPS(self): + def supprPointsGPS(self): # Suppression des points GPS try: self.bulle.destroy() except: pass if self.listePointsGPS.__len__()==0: # pas de points : on sort - self.infoBulle("Aucun point à supprimer !") + self.infoBulle(_("Aucun point à supprimer !")) return - self.actualiseListePointsGPS() # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) + self.actualiseListePointsGPS() # listePointsGPS : 7-tuples (nom du point, x, y et z gps, booléen actif, identifiant) listeIdentifiants = [ (e[0],e[5]) for e in self.listePointsGPS if e[4] ] # liste des noms,identifiants si point non supprimé self.messageSiPasDeFichier = 0 # pour affichage de message dans choisirphoto, difficile a passer en paramètre self.choisirUnePhoto([ f[0] for f in listeIdentifiants], - titre='Points à supprimer', + titre=_('Points à supprimer'), mode='extended', - message="Multiselection possible.", - boutonDeux="Annuler") + message=_("Multiselection possible."), + objets='points', + boutonDeux=_("Annuler")) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin @@ -2713,10 +4772,10 @@ def supprPointsGPS(self): return listeIdentifiantsASupprimer = [g[1] for g in listeIdentifiants if g[0] in self.selectionPhotosAvecChemin] - - for i in self.listePointsGPS: #on met le flag i[4] à zéro : pour conserver le lien avec les points placés ?? + listeIni = list(self.listePointsGPS) + for i in listeIni: # on met le flag i[4] à zéro : pour conserver le lien avec les points placés ?? if i[5] in listeIdentifiantsASupprimer: - self.listePointsGPS.remove(i) + self.listePointsGPS.remove(i) i[4] = False self.listePointsGPS.append(i) dico = dict(self.dicoPointsGPSEnPlace) # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y @@ -2725,50 +4784,70 @@ def supprPointsGPS(self): del self.dicoPointsGPSEnPlace[keys] self.optionsReperes() - + self.onglets.select(self.item650) # active l'onglet (il a été supprimé puis recréé par optionsReperes) def actualiseListePointsGPS(self): # actualise les valeurs saisies pour les points GPS + # n'éxécuter que s'il y a eu saisie de points gps : self.listeWidgetGPS existe ! try: self.bulle.destroy() except: pass dico = dict(self.dicoPointsGPSEnPlace) # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y - for a,nom,x,y,z,ident in self.listeWidgetGPS: + for a,nom,x,y,z,ident,incertitude in self.listeWidgetGPS: for i in self.listePointsGPS: # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) if i[5] == ident: self.listePointsGPS.remove(i) i[0] = nom.get() i[0] = i[0].replace(" ","_") # pour corriger une erreur : l'espace est interdit dans les tag d'item de canvas ! - i[1] = x.get() - i[2] = y.get() - i[3] = z.get() + i[1] = x.get().replace(",",".") # remplace la virgule éventuelle par un point + i[2] = y.get().replace(",",".") + i[3] = z.get().replace(",",".") + i[6] = incertitude.get().replace(",",".") self.listePointsGPS.append(i) for e,v in dico.items(): if e[2]==i[5] and i[0]!=e[0]: # l'identifiant du point placé = identifiant du point gps mais le nom du point est différent - #cela signifie que l'utilisateur à modifié le nom + # cela signifie que l'utilisateur à modifié le nom self.dicoPointsGPSEnPlace[(i[0],e[1],e[2])] = v # ajout d'une entrée quicorrige cette anomalie (on devrait utiliser l'identifiant...) try: - del self.dicoPointsGPSEnPlace[e] # suppression de l'ancienen entrée + del self.dicoPointsGPSEnPlace[e] # suppression de l'ancienne entrée except: pass - if e[2]==i[5] and i[4]==False: #si l'identifiant est identique et le point GPS supprimé alors on supprime le point placé + if e[2]==i[5] and i[4]==False: # si l'identifiant est identique et le point GPS supprimé alors on supprime le point placé try: del self.dicoPointsGPSEnPlace[e] - except: pass + except: pass + ############################# + # sur le modèle pythonique l'élément le plus représenté dans une liste l : x=sorted(set(l),key=l.count)[-1] + # ou pour avoir toute l'info [(valeur,nombre),...] : [(e,a.count(e)) for e in a] + # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + # ce bout de code est dupliqué dans controlePointsGPS et actualiseListePointsGPS + + listePointsPlaces=[e[0] for e in self.dicoPointsGPSEnPlace] + pointsPlaces = [(e,listePointsPlaces.count(e)) for e in listePointsPlaces] + self.pointsPlacesUneFois = [f[0] for f,g in set([(e,pointsPlaces.count(e)) for e in pointsPlaces]) if g==1] + self.pointsPlacesUneFois.sort() + + # Nombre de points placés 2 fois ou plus : + self.pointsPlacesDeuxFoisOuPlus = [f[0] for f,g in set([(e,pointsPlaces.count(e)) for e in pointsPlaces]) if g>1] + ############################# def placerPointsGPS(self): - + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return + self.actualiseListePointsGPS() - if self.controlePoints(): + if self.erreurPointsGPS(): return - liste = list ([(n,ident) for n,x,y,z,actif,ident in self.listePointsGPS if actif]) # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) + + liste = list ([(n,ident) for n,x,y,z,actif,ident,incertitude in self.listePointsGPS if actif]) # listePointsGPS : 7-tuples (nom du point, x, y et z gps, booléen actif, identifiant, incertitude) self.messageSiPasDeFichier = 0 # pour affichage de message dans choisirphoto, difficile a passer en paramètre self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Choisir une photo pour placer les points GPS : ", + self.photosAvecChemin, + message=_("Choisir une photo pour placer les points GPS : "), mode='single', - dicoPoints=self.dicoPointsGPSEnPlace) # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + dicoPoints=self.dicoPointsGPSEnPlace) # dicoPointsGPSEnPlace key = (nom point, photo, identifiant), value = (x,y) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin @@ -2782,46 +4861,88 @@ def placerPointsGPS(self): liste, # liste des identifiants en "string" des points self.dicoPointsGPSEnPlace, # les points déjà placés key = nom point, photo, identifiant ) # value = x,y - try: self.dicoPointsGPSEnPlace = self.calibre.dicoPointsJPG # si pas de retour ! - except: pass + try: + self.dicoPointsGPSEnPlace = self.calibre.dicoPointsJPG # si pas de retour ! + except: + pass - def controlePoints(self): + def erreurPointsGPS(self): # regarde si la liste des points GPS comporte une erreur : nom absent ou en double, retourne True si erreur try: self.bulle.destroy() except: pass - texte = "" - ensemble=set(e[0] for e in self.listePointsGPS if e[4]) # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant) - liste=list(e[0] for e in self.listePointsGPS if e[4]) + texte = str() + ensemble=set(e[0] for e in self.listePointsGPS if e[4]) # listePointsGPS : 6-tuples (nom du point, x, y et z gps, booléen actif, identifiant, incertitude) + liste=list(e[0] for e in self.listePointsGPS if e[4]) if ensemble.__len__()!=liste.__len__(): - texte = "Attention : Des points portent le même nom." + texte = _("Attention : des points portent le même nom : corriger !") if "" in ensemble: - texte = "Attention : un point n'a pas de nom. "+texte - if texte!="": + texte = _("Attention : un point n'a pas de nom. ")+texte + if texte!=str(): + print(_("controle points : ")+texte) self.infoBulle(texte) return True return False + + + def appliquerPointsGPS(self): + + try: self.bulle.destroy() + except: pass + if not os.path.exists(os.path.join(self.repTravail,"AperiCloud.ply")): + self.infoBulle(_("Lancer d'abord tapioca/tapas") + "\n" + _("pour obtenir un nuage non densifié.")) + return + + if self.erreurPointsGPS(): # erreur : nom en double ou point sans nom, affiche une info bulle, retourne True si pb + return + + if self.controlePointsGPS()==False: # les points GPS sont assez nombreux et présents sur assez de photos, retourne False si Pb + self.infoBulle(_("Points GPS non conformes :") + "\n"+self.etatPointsGPS) + return + + if self.finCalibrationGPSOK()==False: # création des fichiers xml qui vont bien (dicoAppuis, mesureAppuis) return False si problème + self.infoBulle(_("Points GPS non conformes :") + "\n"+self.etatPointsGPS) + return + + self.infoBulle(_("Patienter :") + "\n" + _("le nuage est en cours de calibration")) + self.lanceBascule() # calibration suivant les points GPS + + # Apericloud crée le nuage 3D des points homologues puis visualisation : + + self.lanceApericloud() # création d'un nuage de points 3D + self.lanceApericloudMeshlab() # affiche le nuage 3D si il existe + try: self.bulle.destroy() + except: pass + +############################ Calibration par axe, plan et métrique def ligneHorizontale(self): - self.dicoLigneVerticale = dict() # on efface le dico horizontal (l'un ou l'autre) - liste = (("Origine Ox",1),("Extrémité Ox",2)) # liste de tuple nom du point et identifiant du widget - self.messageSiPasDeFichier = 0 # pour affichage de message dans choisirphoto, difficile a passer en paramètre + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return + liste = ((_("Origine Ox"),1),(_("Extrémité Ox"),2)) # liste de tuple nom du point et identifiant du widget + self.messageSiPasDeFichier = 0 # pour affichage de message dans choisirphoto, difficile a passer en paramètre + bulles={} + if self.dicoLigneHorizontale.__len__(): + bulles={list(self.dicoLigneHorizontale.items())[0][0][1]:""} self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Placer une ligne horizontale sur une seule photo : ", + self.photosAvecChemin, + message=_("Placer une ligne horizontale sur une seule photo : "), mode='single', - dicoPoints=self.dicoLigneHorizontale) + dicoPoints=self.dicoLigneHorizontale, + bulles=bulles) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin if self.selectionPhotosAvecChemin.__len__()==0: + print("pas de photos choisie") return - + self.dicoLigneVerticale = dict() # on efface le dico vertical (l'un ou l'autre) horizonVierge = dict() try: if self.selectionPhotosAvecChemin[0]==list(self.dicoLigneHorizontale.items())[0][0][1]: # si l'image choisie est la même on conserve le dico horizonVierge = self.dicoLigneHorizontale # sinon nouveau dico - except: pass + except Exception as e: print(str(e)) self.calibre = CalibrationGPS(fenetre, self.selectionPhotosAvecChemin, # image sur laquelle placer les points liste, # liste des identifiants en "string" des points @@ -2830,28 +4951,34 @@ def ligneHorizontale(self): #il doit y avoir 2 points placés, sinon erreur : try: if self.calibre.dicoPointsJPG.__len__()!=2: - self.infoBulle("il faut placer les 2 points.") + self.infoBulle(_("il faut placer les 2 points.")) return - except: pass - try: self.dicoLigneHorizontale = self.calibre.dicoPointsJPG # si pas de retour ! - except: pass + except Exception as e: print(str(e)) + try: self.dicoLigneHorizontale = self.calibre.dicoPointsJPG # si pas de retour on saute + except Exception as e: print(str(e)) def ligneVerticale(self): - self.dicoLigneHorizontale = dict() # on efface le dico horizontal (l'un ou l'autre) + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return self.messageSiPasDeFichier = 0 # pour affichage de message dans choisirphoto, difficile a passer en paramètre + bulles={} + if self.dicoLigneVerticale.__len__(): + bulles={list(self.dicoLigneVerticale.items())[0][0][1]:""} self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Placer une ligne verticale sur une seule photo : : ", + self.photosAvecChemin, + message=_("Placer une ligne verticale sur une seule photo : : "), mode='single', - dicoPoints=self.dicoLigneVerticale) + dicoPoints=self.dicoLigneVerticale, + bulles=bulles) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin if self.selectionPhotosAvecChemin.__len__()==0: return - - liste = (("Origine Oy",1),("Extrémité Oy",2)) # liste de tuple nom du point et identifiant du widget + self.dicoLigneHorizontale = dict() # on efface le dico horizontal (l'un ou l'autre) + liste = ((_("Origine Oy"),1),(_("Extrémité Oy"),2)) # liste de tuple nom du point et identifiant du widget horizonVierge = dict() try: if self.selectionPhotosAvecChemin[0]==list(self.dicoLigneVerticale.items())[0][0][1]: # si l'image choisie est la même on conserve le dico @@ -2865,21 +4992,26 @@ def ligneVerticale(self): # il doit y avoir 2 points placés, sinon erreur :) try: if self.calibre.dicoPointsJPG.__len__()!=2: - self.infoBulle("il faut placer les 2 points.") + self.infoBulle(_("il faut placer exactement 2 points.")) return except Exception as e: pass try: self.dicoLigneVerticale = self.calibre.dicoPointsJPG # si pas de retour ! except Exception as e: pass def planVertical(self): - - self.planProvisoireHorizontal = str() #un seul plan : le dernier - self.planProvisoireVertical = str() + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return self.messageSiPasDeFichier = 0 + if self.planProvisoireVertical=="planVertical.tif": + bulles = {self.monImage_MaitrePlan:_("Plan vertical")} + else: + bulles = {self.monImage_MaitrePlan:_("Plan horizontal")} self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Une photo pour placer le plan vertical : ", - mode='single') + self.photosAvecChemin, + message=_("Une photo pour placer le plan vertical : "), + mode='single', + bulles=bulles) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin @@ -2887,42 +5019,56 @@ def planVertical(self): if self.selectionPhotosAvecChemin.__len__()==0: return + self.planProvisoireHorizontal = str() #un seul plan : le dernier + self.planProvisoireVertical = str() + self.planProvisoireVertical = "planVertical.tif" #os.path.splitext(self.selectionPhotosAvecChemin[0])+"_planvertical.tif" # Nom du fichier masque, à partir du fichier maître, imposé par micmac self.monImage_MaitrePlan = self.selectionPhotosAvecChemin[0] self.planV = TracePolygone(fenetre, self.monImage_MaitrePlan, self.planProvisoireVertical, - labelBouton="Délimiter un plan vertical") # L'utilisateur peut tracer le masque sur l'image maitre + labelBouton=_("Délimiter un plan vertical")) # L'utilisateur peut tracer le masque sur l'image maitre def planHorizontal(self): - - self.planProvisoireHorizontal = str() #un seul plan : le dernier - self.planProvisoireVertical = str() + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return self.messageSiPasDeFichier = 0 + if self.planProvisoireVertical=="planVertical.tif": + bulles = {self.monImage_MaitrePlan:_("Plan vertical")} + else: + bulles = {self.monImage_MaitrePlan:_("Plan horizontal")} self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Une photo pour placer le plan horizontal : ", - mode='single') + self.photosAvecChemin, + message=_("Une photo pour placer le plan horizontal : "), + mode='single', + bulles=bulles) self.messageSiPasDeFichier = 1 # en retour une liste : self.selectionPhotosAvecChemin if self.selectionPhotosAvecChemin.__len__()==0: - return - + return + + self.planProvisoireHorizontal = str() #un seul plan : le dernier + self.planProvisoireVertical = str() + self.planProvisoireHorizontal = "planHorizontal.tif" # os.path.splitext(self.selectionPhotosAvecChemin[0])+"_planhorizontal.tif" # Nom du fichier masque, à partir du fichier maître, imposé par micmac self.monImage_MaitrePlan = self.selectionPhotosAvecChemin[0] self.planH = TracePolygone(fenetre, self.monImage_MaitrePlan, self.planProvisoireHorizontal, - labelBouton="Délimiter un plan horizontal") # L'utilisateur peut tracer le masque sur l'image maitre + labelBouton=_("Délimiter un plan horizontal")) # L'utilisateur peut tracer le masque sur l'image maitre def placer2Points(self): + if self.photosAvecChemin.__len__()==0: + self.infoBulle(_("Choisir d'abord les photos du chantier.")) + return liste = (("Début",1),("Fin",2)) # liste de tuple nom du point et identifiant du widget self.messageSiPasDeFichier = 0 self.choisirUnePhoto( - self.photosPropresAvecChemin, - message="Choisir deux fois une photo pour placer les 2 points : ", + self.photosAvecChemin, + message=_("Choisir deux fois une photo pour placer les 2 points : "), mode='single', dicoPoints=self.dicoCalibre) self.messageSiPasDeFichier = 1 @@ -2938,87 +5084,203 @@ def placer2Points(self): ajout(photosAvecDistance,os.path.basename(self.selectionPhotosAvecChemin[0])) if photosAvecDistance.__len__()>2: - self.infoBulle("Il y a dèjà 2 images avec des points 'distance'. Supprimer les points sur une des 2 images.") + self.infoBulle(_("Il y a dèjà 2 images avec des points 'distance'. Supprimer les points sur une des 2 images.")) return self.calibre = CalibrationGPS(fenetre, self.selectionPhotosAvecChemin, # image sur laquelle placer les points liste, # liste des identifiants en "string" des points - self.dicoCalibre # les points déjà placés key = nom point, photo, identifiant - ) # value = x,y + self.dicoCalibre # les points déjà placés key = nom point, photo, identifiant + ) # value = x,y try: self.dicoCalibre = self.calibre.dicoPointsJPG # si pas de retour ! except: pass - ################################## LANCEMENT DE MICMAC ########################################################### + ################################## LANCEMENT DE MICMAC ########################################################### def lanceMicMac(self): # vérification du choix de photos, de présence de l'éxécutable, du choix de l'extension, de la copie effective dans le répertoire de travail + + if self.etatDuChantier==5: # Chantier terminé + self.encadre(_("Le chantier %(chant)s est terminé après %(densif)s") % {"chant" : self.chantier, "densif" : self.densification} + ".\n\n"+ + _("Vous pouvez modifier les options puis relancer MicMac."),nouveauDepart='non') + return + + # réinitialisation des variables "locales" définies dans le module + + self.zoomI = "" # pour Malt + # Vérification de l'état du chantier : - # si pas de photos choisies : retour : + # si pas de photo ou pas de répertoire micmac : retour : + + if self.pasDePhoto():return + if self.pasDeMm3d():return + if self.pasDeExiftool():return + + # controle que les options sont correctes (toutes, même si elles ne doivent pas servir) + + retour = self.controleOptions() + if retour!=True: + self.encadre(_("Options incorrectes : corriger") + "\n\n"+retour,nouveauDepart="non") + return + + # pas assez de photos choisies : + + if self.photosAvecChemin.__len__()==2: + message = _("Avec 2 photos MicMac construira difficilement un nuage de point dense.") + "\n" + _("Utiliser l'échelle -1 dans Tapioca pour obtenir un nuage optimal.") + "\n" + retour = self.troisBoutons(titre=_('Avertissement : 2 photos seulement'), + question=message, + b1=_('Continuer'),b2=_('Abandon'),b3=None) # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1, + if retour != 0: + self.afficheEtat() + return + + + # pas enregistré : on enregistre on poursuit + + if self.etatDuChantier==1: # Des photos mais fichier paramètre non encore enregistré, on enregistre et on poursuit + self.enregistreChantier() # sauvegarde du fichier paramètre sous le répertoire du chantier : modif etatduchantier = 2 + + + + + + # on lance Tapioca ou on repart après erreur : Les photos sont-elles correctes ? + + + self.encadre(_("Controle des photos en cours....\nPatienter jusqu'à la fin du controle."),nouveauDepart='non') + self.controlePhotos() + self.menageEcran() + message = str() + if self.dimensionsOK==False: + message = "\n" + _("Les dimensions des photos ne sont pas toutes identiques.") + "\n"+\ + _("Le traitement par MicMac est incertain.") + "\n"+\ + "\n".join([ a+" : "+str(b[0])+" "+str(b[1]) for a, b in self.dimensionsDesPhotos]) + retour = self.troisBoutons(titre=_('Avertissement'),question=message,b1=_('Continuer'),b2=_('Abandon'),b3=None) + if retour != 0: + self.afficheEtat() + return + + if self.pasDeFocales: + + retour = self.troisBoutons(titre=_('Absence de focales'), + question=_("Certaines photos n'ont pas de focales.") + "\n"+ + _("Le traitement echouera probablement.") + "\n"+ + _("Mettre à jour les exifs (menu Outils)"), + b1=_('Continuer'),b2=_('Abandon'),b3=None) # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1, + if retour != 0: + self.afficheEtat() + return - if self.etatDuChantier==0: # pas de photos choisies : avertissement à l'utilisateur - self.encadre("Choisir les photos à traiter avant d'exécuter Micmac.") - return - # pas enregistré : on enregistre on poursuit - if self.etatDuChantier==1: # Des photos mais fichier paramètre non encore enregistré, on enregistre et on poursuit - self.enregistreChantier() # sauvegarde du fichier paramètre sous le répertoire du chantier : modif etatduchantier = 2 - + if self.exifsOK==False and self.pasDeFocales==False and self.etatDuChantier<3 : + if self.calibSeule.get()==False: + message = _("Les focales des photos ne sont pas toutes identiques.") + "\n"+\ + _("Le traitement par MicMac est possible en utilisant une focale pour la calibration intrinsèque de Tapas.") + "\n"+\ + _("Cependant vous pouvez essayer sans cela.") + "\n" + retour = self.troisBoutons(titre=_('Avertissement'),question=message,b1=_('Continuer'),b2=_('Abandon'),b3=None) + if retour != 0: + self.afficheEtat() + return + + if self.assezDePhotos==False: + message += _("Pas assez de photos pour le traitement : il en faut au moins 2.") + self.encadre(message,nouveauDepart='non') + return + # anormal : chantier planté lors de la dernière éxécution : on propose le déblocage mais on sort dans tous les cas if self.etatDuChantier==3: # En principe ne doit pas arriver : plantage en cours d'un traitement précédent - retour = self.deuxBoutons( titre="Le chantier "+self.chantier+" a été interrompu en cours d'exécution.", - question="Le chantier est interrompu.\nVous pouvez le débloquer, "+ - "ce qui permettra de modifier les options et de le relancer.\n", - b1='Débloquer le chantier',b2='Abandon') + retour = self.troisBoutons( titre=_("Le chantier %s a été interrompu en cours d'exécution.") % (self.chantier), + question=_("Le chantier est interrompu.") + "\n" + _("Vous pouvez le débloquer,")+ + _( "ce qui permettra de modifier les options et de le relancer.") + "\n", + b1=_('Débloquer le chantier'),b2=_('Abandon')) if abs(retour)==1: # 1 ou -1 : abandon ou fermeture de la fenêtre par la croix return if retour==0: self.nettoyerChantier() # le chantier est noté comme de nouveau modifiable self.sauveParam() - self.afficheEtat("Chantier "+self.chantier+" de nouveau modifiable, paramètrable et exécutable.") + self.afficheEtat(_("Chantier %s de nouveau modifiable, paramètrable et exécutable.") % (self.chantier)) return # Chantier arrété après tapas : l'utilisateur a pu modifier les options et veut continuer ou reprendre au début suivant les résultats # poursuite du traitement ou arrêt suivant demande utilisateur if self.etatDuChantier==4: # Chantier arrêté après Tapas - retour = self.deuxBoutons( titre='Continuer le chantier '+self.chantier+' après tapas ?', - question = "Le chantier est arrêté après tapas.\nPoursuivre le traitement ou annuler le traitement précédent?\n"+ - "Pour ne rien faire cliquer sur le bouton 'fermer' de la fenêtre", - b1='Poursuivre',b2='Débloquer le chantier - garder les résultats') + + retour = self.troisBoutons( titre=_('Continuer le chantier %s après tapas ?') % (self.chantier), + question = _("Le chantier est arrêté après tapas. Vous pouvez :") + "\n"+ + _(" - lancer Malt, ou C3DC, pour obtenir un nuage dense") + "\n"+ + _(" - débloquer le chantier pour modifier les paramètres de Tapioca/tapas") + "\n"+ + _(" - ne rien faire") + "\n", + b1=_('Lancer ')+self.densification, + b2=_('Débloquer le chantier - garder les résultats'), + b3=_('Abandon')) if retour == -1: # fermeture de la fenêtre + self.afficheEtat(entete=_("abandon de Malt")) return - - if retour == 0: # Lancer malt ou C3DC - self.menageEcran() # ménage écran - self.cadreVide() # fenêtre texte pour affichage des résultats. - self.ajoutLigne(heure()+" Reprise du chantier "+self.chantier+" arrêté aprés TAPAS - La trace depuis l'origine sera disponible dans le menu édition.") + self.cadreVide() # début de la trace : fenêtre texte pour affichage des résultats. + if retour == 0: # b1 : Lancer malt ou C3DC + self.ajoutLigne(heure()+_(" Reprise du chantier %s arrêté aprés TAPAS - La trace depuis l'origine sera disponible dans le menu édition.") % (self.chantier)) self.suiteMicmac() # on poursuit par Malt ou C3DC return - if retour==1: # débloquer le chantier + if retour==1: # b2 : débloquer le chantier self.nettoyerChantier() - self.afficheEtat("Chantier "+self.chantier+" de nouveau modifiable, paramètrable et exécutable.") + self.afficheEtat(_("Chantier %s de nouveau modifiable, paramètrable et exécutable.") % (self.chantier)) return + if retour==2: # b3 : abandon + self.afficheEtat() + return + + # Chantier terminé, l'utilisateur peur décider de le débloquer en conservant les résultats de tapas ou supprimer tous les résultats - - if self.etatDuChantier==5: # Chantier terminé - retour = self.deuxBoutons( titre='Le chantier '+self.chantier+' est terminé.', - question="Le chantier est terminé.\nVous pouvez le nettoyer, "+ - "ce qui supprimera les calculs et permettra de le relancer.\n", - b1='Ne rien faire',b2='Nettoyer le chantier - garder les résultats') - if retour==-1: # -1 : fermeture fenêtre, abandon - return - if retour==0: # 0 : ne rien faire - return - if retour==1: # 1 : on nettoie, on passe à l'état 2 - self.nettoyerChantier() - self.afficheEtat("Chantier "+self.chantier+" de nouveau modifiable, paramètrable et exécutable.") - return + # est-il possible de relancer Malt en conservant le niveau de zoom déjà atteint ??? pas sur, sauf en passant par Micmac +## +## if self.etatDuChantier==5: # Chantier terminé +## if self.densification=="C3DC": +## self.encadre("Le chantier "+self.chantier+" est terminé après "+self.densification+".\n\n"+ +## "Vous pouvez modifier les options puis relancer MicMac.") +## return +## if self.zoomF.get()=="1": +## self.encadre("Le chantier "+self.chantier+" est terminé après "+self.densification+", avec un zoom final de 1.\n\n"+ +## "Vous pouvez modifier les options puis relancer MicMac.") +## return +## +## if self.zoomF.get()=="2": +## retour = self.troisBoutons( titre='Le chantier '+self.chantier+' est terminé.', +## question="Le chantier est terminé après Malt, avec un zoom final de 2.\n"+ +## "Vous pouvez :\n"+ +## " - Relancer MicMac pour obtenir un zoom final de 1\n"+ +## " - Modifier les options avant de relancer MicMac\n"+ +## " - Ne rien faire.\n", +## b1='Zoom final = 1', +## b2='Modifier les options', +## b3='Ne rien faire',) +## if retour==-1: # -1 : fermeture fenêtre, abandon +## self.afficheEtat() +## return +## +## if retour==0: # bouton b1, retour = 0 : on nettoie, on passe à l'état 2 +## self.zoomF.set("1") # zoom final = 1 +## self.zoomI = "4" # zoom Initial = 2 +## self.ajoutLigne(heure()+" Reprise du chantier "+self.chantier+" avec un zoom final = 1.\n") +## self.etatDuChantier=4 # état : arrêt aprés tapas +## self.suiteMicmac() +## return +## +## if retour==1: # retour=1, bouton b2 : modifier les options +## self.optionsOnglet() +## return +## +## if retour==2: # retour=2, bouton b3 : ne rien faire +## self.afficheEtat() +## return + + + # L'état du chantier est prêt pour l'exécution de Tapioca (2) ou débloqué (6) : sauvegarde des paramètres actuels puis traitement self.sauveParam() @@ -3028,47 +5290,57 @@ def lanceMicMac(self): # vérification du c retourAvantScene = self.avantScene() # Efface tout, Prépare le contexte, crée le répertoire de travail, copie les photos, ouvre les traces if retourAvantScene!=None: # Préparation de l'éxécution de MicMac - texte = "Pourquoi MicMac s'arrête : \n"+retourAvantScene + texte = _("Pourquoi MicMac s'arrête : ") + "\n"+retourAvantScene self.encadreEtTrace(texte) # si problème arrêt avec explication return - # Prêt : modification de l'état, lancement du premier module Tapioca (recherche des points homologues) + # Prêt : modification de l'état, lancement du premier module Tapioca (recherche des points homologues) arrêt si pas de points homologues self.etatDuChantier = 3 # trés provisoirement (en principe cette valeur est transitoire sauf si avantScène plante) self.lanceTapioca() if not os.path.exists("Homol"): # le répertoire Homol contient les points homologues, si absent, pas de points en correspondancce - message = "Pourquoi MicMac s'arrête : \n"+"Aucun point en correspondance sur 2 images n'a été trouvé par Tapioca.\n\n"+\ - "Parmi les raisons de cet échec il peut y avoir :\n"+\ - "soit l'exif des photos ne comporte pas la focale ou plusieurs focales sont présentes \n+"+\ - "Soit l'appareil photo est inconnu de Micmac\n"+\ - "soit la qualité des photos est en cause.\n"+\ - "\nUtiliser les items du menu 'outils' pour vérifier ces points.\n\n" + message = _("Pourquoi MicMac s'arrête : ") + "\n"+_("Aucun point en correspondance sur 2 images n'a été trouvé par Tapioca.") + "\n\n"+\ + _("Parmi les raisons de cet échec il peut y avoir :") + "\n"+\ + _("soit l'exif des photos ne comporte pas la focale ou plusieurs focales sont présentes") + "\n+" +\ + _("Soit l'appareil photo est inconnu de Micmac") + "\n"+\ + _("soit la qualité des photos est en cause.") + "\n\n"+\ + _("Utiliser les items du menu 'outils' pour vérifier ces points.") + "\n\n" self.ajoutLigne(message) self.messageNouveauDepart = message - self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peyt-être polluée par le traitement + self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peut-être polluée par le traitement) Ecrit la trace return # points homologues trouvés, second module : Tapas positionne les prises de vue dans l'espace - self.nbResiduTapas = 0 # booléen pour tester si taps fonctionne : si aucune orientation alors échec de tapioca self.lanceTapas() - - if self.nbResiduTapas == 0: # Tapioca n'a pu mettre en correspondance ce aucun point entre deux images : échec - message = "Pourquoi MicMac s'arrête : \n"+"Pas d'orientation trouvé par tapas.\nPrises de vues non positionnées.\n"+\ - "Verifier la qualité des photos (item du menu outil)\n\n" + + if os.path.isdir("Ori-Arbitrary")==False: # Tapioca n'a pu mettre en correspondance ce aucun point entre deux images : échec + message = _("Pourquoi MicMac s'arrête :") + "\n"+_("Pas d'orientation trouvé par tapas.") + "\n" + _("Prises de vues non positionnées.") + "\n"+\ + _("Consulter l'aide (quelques conseils),") + "\n" + _("consulter la trace.") + "\n"+\ + _("Verifier la qualité des photos (item du menu outil)") + "\n\n"+self.messageRetourTapas self.ajoutLigne(message) + self.ecritureTraceMicMac() # on écrit les fichiers trace + self.sauveParam() self.messageNouveauDepart = message - self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peyt-être polluée par le traitement + self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peut-être polluée par le traitement) Ecrit la trace return + # Si un fichier de calibration par axe plan et métrique est valide on lance apero, même s'il y a une calibration par points GPS (sera bon si GPS échoue) - # Si un fichier de calibration valide est présent on lance apero - - if self.controleCalibration(): # calibration OK + if self.controleCalibration(): # calibration OK = True self.lanceApero() - if self.etatCalibration!=str(): # calibration incomplète - self.ajoutLigne(heure()+"Calibration incomplète : "+self.etatCalibration) + if self.etatCalibration!=str(): # calibration incomplète s'il y a un message, motif dans etatCalibration + self.ajoutLigne(heure()+_("Calibration incomplète : ")+self.etatCalibration) + + + # calibrage de l'orientation suivant des points GPS, un axe ox, un plan déterminé par un masque + # si il existe un fichier XML de points d'appuis : self.mesureAppuis + + if os.path.exists(self.mesureAppuis): + + self.lanceBascule() # des points GPS : on calibre dessus, cela remplace la calibration précédente + # troisième module : Apericloud crée le nuage 3D des points homologues puis visualisation : @@ -3076,124 +5348,170 @@ def lanceMicMac(self): # vérification du c self.lanceApericloudMeshlab() # affiche le nuage 3D si il existe # Situation stable, changement d'état : 4 = Tapioca et Tapas exécutés, sauvegarde des paramètres - - self.etatDuChantier = 4 # état du chantier lors de l'arrêt aprés tapas - self.sauveParam() + + if os.path.exists('AperiCloud.ply'): + self.etatDuChantier = 4 # état du chantier lors de l'arrêt aprés tapas + self.copierParamVersChantier() # sauvegarde du fichier paramètre sous le répertoire du chantier self.ecritureTraceMicMac() # on écrit les fichiers trace + + # tarama ? + if self.lancerTarama.get(): # mosaïque ? + self.lanceTarama() # Faut-il poursuivre ? - + if self.arretApresTapas.get(): # L'utilisateur a demandé l'arrêt - ligne="\nArrêt après Tapas "+heure()+". Lancer MicMac pour reprendre le traitement. \n" - ligne=ligne+"\n\n************* Arrêt aprés Tapas sur demande utilisateur *******************\n\n" + ligne="\n" + _("Arrêt après Tapas ")+heure()+_(". Lancer MicMac pour reprendre le traitement.") + "\n" + ligne=ligne+"\n\-------------- " + _("Arrêt aprés Tapas sur demande utilisateur") + " --------------\n\n" self.ajoutLigne(ligne) - self.copierParamVersChantier() # sauvegarde du fichier paramètre sous le répertoire du chantier + self.nouveauDepart() # sauvegarde les paramètres, écrit la trace, relance "interface" si on est sous nt + return else: self.suiteMicmac() # PoursSuite : Malt ou C3DC, pouvant être appelé directement - self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peyt-être polluée par le traitement - - def nettoyerChantier(self): # Le chantier est nettoyé : les résulats sous reptravail sont conservés, les arborescences de calcul effacés - self.etatDuChantier = 2 - self.enregistreChantier() - listeAConserver = os.listdir(self.repTravail) - supprimeArborescenceSauf(self.repTravail,listeAConserver) - def suiteMicmac(self): - + def suiteMicmac(self): # poursuite aprés tapas, avec ou sans arrêt aprés tapas, retour au menu - #on ne peut poursuivre que si il existe un fichier "apericloud.ply", et une image maitresse, 2D ou 3D. + # on ne peut poursuivre que si il existe un fichier "apericloud.ply", et une image maîtresse, 2D ou 3D. if os.path.exists("AperiCloud.ply")==False: - ligne = ("Tapas n'a pas généré de nuage de points.\n"+ - "Le traitement ne peut se poursuivre.\n"+ - "Vérifier la qualité des photos, modifier les paramètres et relancer tapioca-tapas") - self.ajoutLigne(ligne) - self.encadre(ligne) + ligne = (_("Tapas n'a pas généré de nuage de points.") + "\n"+ + _("Le traitement ne peut se poursuivre.") + "\n"+ + _("Vérifier la qualité des photos, modifier les paramètres et relancer tapioca-tapas")) + self.encadre(ligne,nouveauDepart='non') return - if not(self.existeMasque3D() or self.existeMasque2D()): - ligne = ("Pas de masque, 2D ou 3D, généré pour Malt.\n"+ - "Le traitement ne peut se poursuivre.\n"+ - "Changer le mode 'GeomImage' qui impose un masque\n"+ - "ou définir un masque 2D ou 3D (item option/Malt ou C3DC)\n") - self.ajoutLigne(ligne) - self.encadre(ligne) + if not(self.existeMasque3D() or self.existeMaitre2D()): + ligne = (_("Pas de masque 3D, ou d'image maîtresse pour Malt.") + "\n"+ + _("Le traitement ne peut se poursuivre.") + "\n"+ + _("Définir une image maîtresse") +"\n"+ + _("ou Changer le mode 'GeomImage' qui impose une image maîtresse") + "\n"+ + _("ou définir un masque 3D") + "\n"+ + _("Pour cela utiliser l'item option/Malt ou option/C3DC du menu MicMac") + "\n") + self.encadre(ligne,nouveauDepart='non') return - - # calibrage de l'orientation suivant des points GPS, un axe ox, un plan déterminé par un masque + + # calibrage de l'orientation suivant des points GPS (possiblement modifiés aprés tapas) # si il existe un fichier XML de points d'appuis : self.mesureAppuis if os.path.exists(self.mesureAppuis): self.lanceBascule() - + + + # Si un modele3D existe déjà on le renomme pour le conserver (limité à 20 exemplaire !) + + if os.path.exists("modele3D.ply"): + for i in range(1,20): + new = "modele3D_V"+str(i)+".ply" + if not os.path.exists(new): + try: + os.replace(os.path.join(self.repTravail,"modele3D.ply"),os.path.join(self.repTravail,new)) + self.ajoutLigne("\n" + _("Le fichier modele3D.ply précédent est renommé en ")+new+".") + except Exception as e: + print(_("erreur renommage ancien modele_3d en "),new,str(e)) + self.ajoutLigne("\n" + _("Le fichier Modele3D.ply précédent n'a pu être renommé. Il sera remplacé.")) + break + # malt ou D3CD : suivant que le masque 3 D existe ou pas, avec préférence au masque 3D, - # la production sera "modele3D.ply" + # la production sera self.modele3DEnCours if self.existeMasque3D(): - self.sauveParam() - self.lanceC3DC() # C3DC crée directement le fichier modele3D.ply + self.lanceC3DC() # C3DC crée directement le fichier self.modele3DEnCours else: self.suiteMicmacMalt() - if self.modeMalt.get()=="GeomImage": - self.lanceNuage2PlyGeom() - if self.modeMalt.get()=="UrbanMNE": - self.lanceNuage2PlyUrban() - if self.modeMalt.get()=="Ortho": - self.lanceNuage2PlyUrban() - # Final : affichage du modele3D.ply, sauvegarde, relance la fenêtre qui a pu être dégradé par le traitement externe + # Final : affichage du self.modele3DEnCours, sauvegarde, relance la fenêtre qui a pu être dégradé par le traitement externe - retour = self.lanceMeshlab() + retour = self.ouvreModele3D() texte = "" if retour == -1 : - texte = "Pas de nuage de points aprés Malt ou C3DC." + texte = _("Pas de nuage de points aprés Malt ou C3DC.") if retour == -2 : - texte = "Programme pour ouvrir les .PLY non trouvé." - ligne = texte + "\n\n************* Fin du traitement MicMac "+heure()+" *******************\n\n" - self.etatDuChantier = 5 # 5 : chantier terminé + texte = _("Programme pour ouvrir les .PLY non trouvé.") + ligne = texte + "\n\n-------------- " + _("Fin du traitement MicMac ")+heure()+" --------------\n\n" self.ajoutLigne(ligne) - + self.etatDuChantier = 5 # 5 : chantier terminé + self.messageNouveauDepart = texte + self.nouveauDepart() # sauvegarde les paramètres, écrit la trace, relance "interface" si on est sous nt (nécessaire : suiteMicmac doit être autonome) + # Que faire après Tapioca et Tapas ? malt ou D3DC def suiteMicmacMalt(self): - if self.etatDuChantier==4: # en principe inutile : toujours vrai ! - if self.avantMalt()!=None: # copie l'image maitresse et le masque, sauve les paramètres - self.messageNouveauDepart = "Pourquoi MicMac est arrêté : \n"+self.avantMalt()+"\n Corriger." - self.ajoutLigne(self.messageNouveauDepart) - self.ecritureTraceMicMac() - return - self.lanceMalt() - else: - self.ajoutLigne("Tapas non effectué, lancer Micmac depuis le menu. Etat du chantier = ",self.etatDuChantier) - + if self.etatDuChantier!=4: # en principe inutile : il faut être juste aprés tapas (toujours vrai ici) ! + self.ajoutLigne(_("Tapas non effectué, lancer Micmac depuis le menu. Etat du chantier = "),self.etatDuChantier) + return -##############################################################################################################" - - def avantMalt(self): + # il faut une image maîtresse si le mode est geoimage + + if self.listeDesMaitresses.__len__()==0 and self.modeMalt.get()=="GeomImage": # self.photoMaitre : nom de la photo sans extension ni chemin, l'extension est dans self.extensionChoisie + message = ( _("Pourquoi MicMac est arrêté :")+ + "\n" + _("Pas d'image maîtresse.")+ + "\n" + _("Celle-ci est nécessaire pour l'option choisie geomImage de Malt.")+ + "\n" + _("Pour corriger modifier les options de Malt ou choississez un masque 3D avec C3DC.")+ + "\n" + _("Corriger.")) + self.ajoutLigne(message) + self.ecritureTraceMicMac() + self.afficheEtat(message) + return - # initialisation C3DC permet d'utiliser un masque e la photo maitresse pour MALT : il faut une image maitresse si le mode est geoimage + # si le mode est UrbanMne ou Ortho on lance simplement Malt - if self.maitreSansChemin=='' and self.modeMalt.get()=="GeomImage": # self.photoMaitre : nom de la photo sans extension ni chemin, l'extension est dans self.extensionChoisie - return "Pas d'image maîtresse.\nCelle-ci est nécessaire pour l'option choisie geomImage de Malt.\nPour corriger modifier les options de Malt ou choississez un masque 3D avec C3DC." - - # copie du fichier masque, s'il existe, pour accélérer MALT ( MicMac recherche un fichier de nom "fixé", suivant le nom de l'image maitresse - self.nomMaitreSansExtension = os.path.splitext(self.maitreSansChemin)[0] # utile pour nuage2ply - - if os.path.exists(self.masque): - try: shutil.copy(self.masque,self.repTravail) # on copie le masque - except: pass - try: shutil.copy(self.fichierMasqueXML,self.repTravail) # copie du fichier XML Associé au masque - except: pass - self.ajoutLigne("Fichier masque associé à l'image maitresse pour la procédure MALT : \n\n" - +self.masqueSansChemin+"\n\n") # PROBLEME SI L'EXTENSION CHOISIE pour les photos EST TIF - else: - self.ajoutLigne("\nPas de masque associé à l'image maîtresse.\n") - - self.sauveParam() - - + if self.modeMalt.get() in ("UrbanMNE","Ortho"): + self.lanceMalt() + self.lanceTawny() + self.tousLesNuages() + + # création de modele3D.ply (self.modele3DEnCours= dernier ply généré par tousLesNuages) + try: shutil.copy(self.modele3DEnCours,"modele3D.ply") + except Exception as e: self.ajoutLigne(_("Erreur copie modele3D.ply")) + self.modele3DEnCours = "modele3D.ply" # nécessaire pour l'affichage + return + + # si le mode est GeomImage il faut lancer Malt sur chaque Image Maitresse et préparer le résultat + + # Cas GeomImage : il faut traiter toutes les images maitresses : + + if self.modeMalt.get() in ("GeomImage"): + self.nuagesDenses = list() # liste des nuages denses de tous les masques pour fusion en fin de boucle + for e in self.listeDesMaitresses: + self.maitreSansChemin = os.path.basename(e) + self.MasqueXML() # préparation du masque et du maitre + self.lanceMalt() # création du nuage de points + self.tousLesNuages() # création des .ply à tous les niveaux, ajout du plus dense dans la liste + ajout(self.nuagesDenses,self.modele3DEnCours) # le dernier modele3dEncours est le plus dense + + # création de modele3D.ply + self.modele3DEnCours = "modele3D.ply" # nécessaire pour l'affichage + if self.nuagesDenses.__len__()==1: + try: shutil.copy(self.nuagesDenses[0],self.modele3DEnCours) + except Exception as e: print(_("erreur malt GeomImage copy de nuage en modele3D : "),str(e),_(" pour : "),self.nuagesDenses[0]) + else: + try: self.fusionnerPly(self.nuagesDenses,self.modele3DEnCours) + except Exception as e: print(_("erreur malt GeomImage fusion des nuages en modele3D : "),str(e),_(" pour : "),"\n".join(self.nuagesDenses[0])) + + # Cas AperoDeDenis : on construit la liste des images maitresses et des images associées + + if self.modeMalt.get() in ("AperoDeDenis"): + self.nuagesDenses = list() # liste des nuages denses de tous les masques pour fusion en fin de boucle + self.maltApero() # Construit la liste self.maitressesEtPhotoApero [(maitresse,photo),...] + for e,f in self.maitressesEtPhotoApero: + self.maitreSansChemin = e + self.photosApero = [f,e] # pour l'instant une seule photo + self.MasqueXML() # les masques sont saisis avec l'option GeomImage et le nom de l'image maitresse + self.lanceMalt() # création du nuage de points + self.tousLesNuages() # création des .ply à tous les niveaux, ajout du plus dense dans la liste + ajout(self.nuagesDenses,self.modele3DEnCours) # le dernier modele3dEncours est le plus dense + + # création de modele3D.ply + self.modele3DEnCours = "modele3D.ply" # nécessaire pour l'affichage + if self.nuagesDenses.__len__()==1: + try: shutil.copy(self.nuagesDenses[0],self.modele3DEnCours) + except Exception as e: print(_("erreur malt AperoDeDenis copy de nuage en modele3D : "),str(e),_(" pour : "),self.nuagesDenses[0]) + else: + try: self.fusionnerPly(self.nuagesDenses,self.modele3DEnCours) + except Exception as e: print(_("erreur malt AperoDeDenis fusion des nuages en modele3D : "),str(e),_(" pour : "),"\n".join(self.nuagesDenses[0])) + ################################## LES DIFFENTES PROCEDURES MICMAC ########################################################### # ------------------ PREAMBULE -------------------- @@ -3205,30 +5523,24 @@ def avantScene(self): # vérification nécessaires : if len(self.photosAvecChemin)==0: # photos sans chemin - texte='Aucune photo choisie. Abandon.' + texte=_('Aucune photo choisie. Abandon.') return texte if len(self.photosAvecChemin)==1: # photos sans chemin - texte='Une seule photo choisie. Abandon.' - return texte - - # si pas de chemin pour micmac on le demande : - - if not(os.path.exists(self.mm3d)): - texte='mm3d non trouvé : \n'+self.mm3d+'\nVeuillez indiquer le répertoire \\bin de MicMac (menu paramètres)' + texte=_('Une seule photo choisie. Abandon.') return texte - - if self.controleOptions()!=True: - return "\nOption incorrecte :\n"+str(self.controleOptions()) + retour = self.controleOptions() + if retour!=True: + return "\n" + _("Option incorrecte :") + "\n"+str(retour) - self.lignePourTrace = "****************************** TRACE DETAILLEE ****************************\n" # première ligne de la trace détaillée - self.ligneFiltre = "****************************** TRACE SYNTHETIQUE ****************************\n" # première ligne de la trace synthétique + self.lignePourTrace = ("-------------- " + _("TRACE DETAILLEE") + " **--------------\n") # première ligne de la trace détaillée + self.ligneFiltre = ("-------------- " + _("TRACE SYNTHETIQUE") + " --------------\n") # première ligne de la trace synthétique - texte='------------------------- DEBUT DU TRAITEMENT MICMAC ---- '+heure()+' ----------------------------------------\n\n\n' + texte = "-------------- " + _("DEBUT DU TRAITEMENT MICMAC à ")+ heure()+" -------------- \n\n" - photosPropres=list([os.path.basename(x) for x in self.photosPropresAvecChemin]) - texte = texte+'Photos choisies : \n\n'+'\n'.join(photosPropres)+'\n\n' - texte = texte+"Ces photos sont recopiées dans le répertoire du chantier : \n\n"+self.repTravail+'\n\n' + photosPropres=list([os.path.basename(x) for x in self.photosAvecChemin]) + texte = texte+_('Photos choisies :') + " \n\n"+'\n'.join(photosPropres)+'\n\n' + texte = texte+_("Ces photos sont recopiées dans le répertoire du chantier :") + "\n\n"+self.repTravail+'\n\n' self.ajoutLigne(texte) @@ -3238,7 +5550,7 @@ def avantScene(self): def lanceTapioca(self): - self.etape = 0 + self.etapeTapioca = 0 if self.modeTapioca.get()=="All": self.echelle1PourMessage = self.echelle1.get() tapioca = [self.mm3d, @@ -3246,7 +5558,7 @@ def lanceTapioca(self): self.modeTapioca.get(), '.*'+self.extensionChoisie, self.echelle1.get(), - "ExpTxt=0"] + "ExpTxt="+self.exptxt] if self.modeTapioca.get()=="MulScale": self.echelle1PourMessage = self.echelle2.get() @@ -3257,7 +5569,7 @@ def lanceTapioca(self): '.*'+self.extensionChoisie, self.echelle2.get(), self.echelle3.get(), - "ExpTxt=0"] + "ExpTxt="+self.exptxt] if self.modeTapioca.get()=="Line": self.echelle1PourMessage = self.echelle4.get() @@ -3267,10 +5579,10 @@ def lanceTapioca(self): '.*'+self.extensionChoisie, self.echelle4.get(), self.delta.get(), - "ExpTxt=0"] + "ExpTxt="+self.exptxt] self.lanceCommande(tapioca, - self.filtreTapioca) + filtre=self.filtreTapioca) def filtreTapioca(self,ligne): @@ -3282,40 +5594,107 @@ def filtreTapioca(self,ligne): return ligne if 'matches' in ligne: return ligne - if 'utopano' in ligne and self.etape==0: # début de la première étape sur la première échelle - self.etape+=1 - return heure()+"Recherche des points remarquables et des correspondances sur une image de taille "+self.echelle1PourMessage+" pixels.\n\n" - if 'utopano' in ligne and self.etape==1: # début de la seconde étape sur la seconde échelle - self.etape+=1 + if 'utopano' in ligne and self.etapeTapioca==0: # début de la première étape sur la première échelle + self.etapeTapioca += 1 + return heure()+"\n" + _("Recherche des points remarquables et des correspondances sur une image de taille %s pixels.") % (self.echelle1PourMessage)+ "\n\n" + if 'utopano' in ligne and self.etapeTapioca==1: # début de la seconde étape sur la seconde échelle + self.etapeTapioca += 1 if self.echelle2PourMessage=="-1": - return "\nRecherche des points remarquables et des correspondances sur l'image entière.\n\n" + return "\n" + _("Recherche des points remarquables et des correspondances sur l'image entière.") + "\n\n" if self.echelle2PourMessage!="": - return "\nRecherche des points remarquables et des correspondances sur une image de taille "+self.echelle2PourMessage+" pixels.\n\n" + return "\n" + _("Recherche des points remarquables et des correspondances sur une image de taille %s pixels.") % (self.echelle2PourMessage) + "\n\n" return ligne - # ------------------ TAPAS ----------------------- + # ------------------ TAPAS ----------------------- Avec ou sans calibrationj intrinsèque def lanceTapas(self): + + self.messageRetourTapas = str() + if self.photosPourCalibrationIntrinseque.__len__()>0: # s'il y a des photos pour calibration intrinsèque + self.photosCalibrationSansChemin = [os.path.basename(f) for f in self.photosPourCalibrationIntrinseque] + if self.photosCalibrationSansChemin.__len__()==1: + self.messageRetourTapas = _("Une seule photo pour la calibration intrinsèque : insuffisant.") + "\n" + self.ajoutLigne(self.messageRetourTapas) + return + + self.ajoutLigne(_("Calibration intrinsèque lancée sur les photos : ") + "\n"+str("\n".join(self.photosCalibrationSansChemin)+"\n")) + + # limitation aux seules images pour la calibration : + + [os.rename(e,os.path.splitext(e)[0]) for e in self.photosSansChemin if e not in self.photosCalibrationSansChemin] + + tapas = [self.mm3d, + "Tapas", + self.modeCheckedTapas.get(), + '.*'+self.extensionChoisie, + "Out=Calib", + "ExpTxt="+self.exptxt] + self.lanceCommande(tapas, + filtre=self.filtreTapas, + info=_("Calibration intrinsèque, pour trouver les réglages de l'appareil photo sur quelques photos") + "\n" + _("Recherche d'un point de convergence au centre de l'image.") + "\n\n") + + # Remise en état initial des photos pour calibration + [os.rename(os.path.splitext(e)[0],e) for e in self.photosSansChemin if e not in self.photosCalibrationSansChemin] + + if os.path.isdir("Ori-Calib")==False: + self.messageRetourTapas = _("La calibration intrinsèque n'a pas permis de trouver une orientation.") + "\n" + self.ajoutLigne(self.messageRetourTapas) + return + self.ajoutLigne(_("Calibration intrinsèque effectuée.")) + + + if self.photosSansChemin.__len__()-self.photosCalibrationSansChemin.__len__()<2 and self.calibSeule.get(): + self.messageRetourTapas = _("Une seule photo pour Tapas sans les photos de calibration : insuffisant.") + "\n" + self.ajoutLigne(self.messageRetourTapas) + return + + ##################################################### + + # exclusion des images pour la calibration si elles ne servent plus après : + + if self.calibSeule.get(): + try : os.mkdir(self.repCalibSeule) + except: pass + [os.rename(e,os.path.join(self.repCalibSeule,e)) for e in self.photosCalibrationSansChemin] # déplacer photocalibration pour les traitements suivant + self.photosAvecChemin = [f for f in self.photosAvecChemin if os.path.basename(f) not in self.photosCalibrationSansChemin] + self.photosSansChemin = [os.path.basename(g) for g in self.photosAvecChemin] + self.photosPourCalibrationIntrinseque = [os.path.join(self.repTravail,self.repCalibSeule,e) for e in self.photosCalibrationSansChemin] + else: + print("self.calibSeule.get()=",self.calibSeule.get()) + + ##################################################### + + tapas = [self.mm3d, + "Tapas", + self.modeCheckedTapas.get(), + '.*'+self.extensionChoisie, + 'InCal=Calib', + 'Out=Arbitrary', + "ExpTxt="+self.exptxt] + self.lanceCommande(tapas, + filtre=self.filtreTapas, + info=_("Recherche l'orientation des prises de vues") + "\n\n") - tapas = [self.mm3d, - "Tapas", - self.modeCheckedTapas.get(), - '.*'+self.extensionChoisie, - 'Out=Arbitrary', - 'ExpTxt=0'] - self.lanceCommande(tapas, - self.filtreTapas, - "Calibration, pour trouver les réglages intrinsèques de l'appareil photo\nRecherche d'un point de convergence au centre de l'image.\n\n" ) + else: + + tapas = [self.mm3d, + "Tapas", + self.modeCheckedTapas.get(), + '.*'+self.extensionChoisie, + 'Out=Arbitrary', + "ExpTxt="+self.exptxt] + self.lanceCommande(tapas, + filtre=self.filtreTapas, + info=_("Calibration, pour trouver les réglages intrinsèques de l'appareil photo") + "\n" + _("Recherche l'orientation des prises de vue.") + "\n\n" ) def filtreTapas(self,ligne): - if 'RESIDU LIAISON MOYENS' in ligne: - self.nbResiduTapas = 1 + if ('RESIDU LIAISON MOYENS' in ligne) or ('Residual' in ligne) : # Residual pour la version 5999 return ligne if ligne[0]=="|": return ligne return - # ------------------ APERO + # ------------------ APERO : orientation par axe, plan et métrique, le nom de l'orientation est "echelle3" (attention : polysème) def lanceApero(self): @@ -3323,28 +5702,33 @@ def lanceApero(self): "Apero", os.path.basename(self.miseAEchelle)] self.lanceCommande(apero, - info="Fixe l'orientation (axe et plan) et met à l'échelle en fonction des options 'calibration'") + info=_("Fixe l'orientation (axe,plan et métrique) suivant les options de 'calibration'")) - # ------------------ APERICLOUD ----------------------- + # ------------------ APERICLOUD : ----------------------- + # l'orientation en entrée est soit : + # - Arbitrary (pas de calibration) + # - echelle3 (calibration par axe plan et métrique + # - bascul (calibration par points gps) def lanceApericloud(self): + apericloud=[self.mm3d, "AperiCloud", '.*'+self.extensionChoisie, self.orientation(), - "Out=AperiCloud.ply", - "ExpTxt=0"] + "Out=AperiCloud.ply", # c'est d'ailleurs la valeur par défaut pour AperiCloud + "ExpTxt="+self.exptxt] self.lanceCommande(apericloud, - self.filtreApericloud, - "Positionne les appareils photos autour du sujet.\n\Création d'un nuage de points grossier.") - + filtre=self.filtreApericloud, + info=_("Positionne les appareils photos autour du sujet.") + "\n" + _("Création d'un nuage de points grossier.")) + def filtreApericloud(self,ligne): if ligne[0]=="|": return ligne if "cMetaDataPhoto" in ligne: - print("ligne avec meta : ",ligne) - return "\n#### ATTENTION : Des Metadonnées nécessaires sont absentes des photos. Vérifier l'exif.\n\n" + print(_("ligne avec meta : "),ligne) + return "\n####" + _("ATTENTION : des metadonnées nécessaires sont absentes des photos. Vérifier l'exif.") + "\n\n" # ------------------ Meslab 1 : ouvre AperiCloud.ply avec l'outil choisi par l'utilisateur -------------------------- @@ -3355,184 +5739,467 @@ def lanceApericloudMeshlab(self): # ouvre le ply créé pa open_file('AperiCloud.ply') return self.lanceCommande([self.meshlab,'AperiCloud.ply'], - info="Ouverture du nuage de points après Apericloud", + info=_("Ouverture du nuage de points après Apericloud"), attendre=False) else: - texte="\nPas de fichier AperiCloud.ply généré.\n" + texte="\n" + _("Pas de fichier AperiCloud.ply généré.") + "\n" self.ajoutLigne(texte) - self.messageNouveauDepart = texte+"Consulter la trace.\n" + self.messageNouveauDepart = texte+_("Consulter l'aide (quelques conseils),\nConsulter la trace.") + "\n" return -1 + # ------------------ Tarama----------------------- crée TA_LeChantier.tif sous le répertoire TA - def lanceBascule(self): + def lanceTarama(self): + self.ajoutLigne("\n\n---------------------------\n" + _("Tarama : mosaïque des photos d'aprés les tie points") + "\n") + tarama = [ self.mm3d, + "Tarama", + '.*'+self.extensionChoisie, + "Arbitrary"] + self.lanceCommande(tarama) + + # ------------------ GCPBascule : utilise les points GPS----------------------- + + def lanceBascule(self): # une alternative est Campari + + self.ajoutLigne("\n\n---------------------------\n" + _("Prise en compte des points GPS : nécessite au minimum 3 points, chacun sur 2 photos") + "\n") + if len(self.dicoPointsGPSEnPlace)<6: + self.ajoutLigne("\n" + _("Le nombre minimum de points placés sur les photos n'est pas atteint. Abandon.") + "\n") + return GCPBascule = [ self.mm3d, "GCPBascule", '.*'+self.extensionChoisie, - self.orientation(), - "bascul", + "Arbitrary", # orientation obtenue aprés tapas, nuage non densifié + "bascul", # Orientation calibrée par les points GPS, utilisé par Mlat ou C3DC os.path.basename(self.dicoAppuis), os.path.basename(self.mesureAppuis)] - self.lanceCommande(GCPBascule) + self.lanceCommande(GCPBascule, + filtre=self.filtreGCPBascule) - + def filtreGCPBascule(self,ligne): + if "MAX" in ligne: # dans la version xxxx il y a ERRROR ! + return ligne + if "||" in ligne: + return ligne + # ------------------ MALT ----------------------- - def lanceMalt(self): - malt = [self.mm3d, - "Malt", - self.modeMalt.get(), - ".*"+self.extensionChoisie, - self.orientation(), - "Master="+self.maitreSansChemin] + def lanceMalt(self): # malt prend les points homologues dans le répertoire "Homol", + # et si geoImage : l'image maîtresse dans self.maitreSansChemin (str() si absent) + # et dans self.photosSansChemin les images autour de l'image maitressse + # si il y a un masque il faut les 2 fichiers maitre_Masq.xml et maitre_Masq.tif sans les indiquer dans la syntaxe + + self.ajoutLigne("\n\n---------------------------\n" + _("Préparation du lancement de Malt") + "\n") + self.densification = "Malt" + aConserver = str() + if self.modeMalt.get()=="GeomImage": + # Les N meilleurs fichiers en correspondances avec la maitresse + aConserver = self.meilleuresPhotosAutourMaitresse(self.maitreSansChemin,self.photosUtilesAutourDuMaitre.get()) + # on renomme les autres + if aConserver: + [os.rename(e,os.path.splitext(e)[0]) for e in self.photosSansChemin if e not in aConserver] + self.ajoutLigne("\n\n"+_("Photos utiles pour malt GeomImage : ")+aConserver+"\n") + else: + self.ajoutLigne("\n\n"+_("Malt sur toutes les photos")) + malt = [self.mm3d, + "Malt", + self.modeMalt.get(), + ".*"+self.extensionChoisie, # les n meilleures photos en correspondance, les autres étant renommées + self.orientation(), + "NbVI=2", + "ZoomF="+self.zoomF.get(), + "Master="+self.maitreSansChemin] + elif self.modeMalt.get()=="AperoDeDenis": + # Les N fichiers en correspondances avec la maitresse sont dans la variable self.photosApero + [os.rename(e,os.path.splitext(e)[0]) for e in self.photosSansChemin if e not in self.photosApero] + self.ajoutLigne("\n\n"+_("Photos utiles pour malt AperoDeDenis : ")+str(self.photosApero)+"\n") + malt = [self.mm3d, + "Malt", + "GeomImage", + ".*"+self.extensionChoisie, # les n meilleures photos en correspondance, les autres étant renommées + self.orientation(), + "NbVI=2", + "ZoomF="+self.zoomF.get(), + "Master="+self.maitreSansChemin] + elif self.modeMalt.get()=="Ortho": + if os.path.exists(self.masqueTarama): + self.ajoutLigne("\n\n"+_("Mosaique et masque: ")+str(self.mosaiqueTaramaTIF)+"\n") + else: + self.ajoutLigne("\n\n"+_("Mosaique seule : ")+str(self.mosaiqueTaramaTIF)+"\n") + malt = [self.mm3d, + "Malt", + "Ortho", + ".*"+self.extensionChoisie, # les n meilleures photos en correspondance, les autres étant renommées + self.orientation(), + "NbVI=2", + "ZoomF="+self.zoomF.get(), + 'DirTA=TA'] + + else: + malt = [self.mm3d, + "Malt", + self.modeMalt.get(), + ".*"+self.extensionChoisie, + self.orientation(), + "NbVI=2", + "ZoomF="+self.zoomF.get()] # zoom 8,4,2,1 qui correspondent au nuage étape 5, 6, 7, 8 + self.lanceCommande(malt, - self.filtreMalt, - "ATTENTION : cette procédure est longue : patience !") - + filtre=self.filtreMalt, + info=_("ATTENTION : cette procédure est longue : patience !")) + + if aConserver or self.modeMalt.get()=="AperoDeDenis": # on renomme correctement les fichiers abandonnés pour le traitement de malt + [os.rename(os.path.splitext(e)[0],e) for e in self.photosSansChemin if (os.path.exists(os.path.splitext(e)[0]) and not (os.path.exists(e)))] + + def filtreMalt(self,ligne): if ligne[0]=="|": return ligne if 'BEGIN BLOC' in ligne: return ligne + + def reinitialiseMaitreEtMasque(self): # on conserve si la photo appartient au nouveau lot + self.masqueSansChemin = str() # image masque : en TIF, choisi par l'utilisateur + self.maitre = str() + self.maitreSansChemin = str() # image maîtresse + self.fichierMasqueXML = str() # nom du fichier XML décrivant le masque + self.maitreSansExtension = str() + self.monImage_MaitrePlan = str() # Nom de l'image maîtresse du plan repere (sans extension) + self.monImage_PlanTif = str() # nom du masque correspondant + self.listeDesMaitresses = list() # liste des images maitresses + self.listeDesMasques = list() # liste Des Masques associès aux maîtresses + self.listeDesMaitresses = list() + self.listeDesMasques = list() + self.miseAJourItem701_703() # met à jour les windgets de l'onglet Malt + + def reinitialiseMaitreEtMasqueDisparus(self): # on conserve les options si la photo appartient au nouveau lot (photos = liste avec chemins) + + self.masqueSansChemin = str() # image masque : en TIF, choisi par l'utilisateur + self.maitre = str() + self.maitreSansChemin = str() # image maîtresse + self.fichierMasqueXML = str() # nom du fichier XML décrivant le masque + self.maitreSansExtension = str() + + # les axes horizontal et vertical conservé si les photos sont présentes ainsi que les maitresses et les masques et le plan et la distance + photos = self.photosAvecChemin + + # Ligne horizontale ou verticale + # axe horizontal, dans le dico : self.dicoLigneHorizontale. key = nom point, photo, identifiant ;Retrouver nom de la photo, coordonnées des points + # items = liste de tuple (key,values) soit tuple = (point,photo, id),(x1,y1) + + if self.dicoLigneHorizontale.__len__()>0: + photosAvecLigneH = [e[1] for e in self.dicoLigneHorizontale.keys()][0] + + if photosAvecLigneH not in photos: + self.dicoLigneHorizontale = dict() + + if self.dicoLigneVerticale.__len__()>0: + photosAvecLigneV = [e[1] for e in self.dicoLigneVerticale.keys()][0] + if photosAvecLigneV not in photos: + self.dicoLigneVerticale = dict() + + # maitre plan et image + + if self.monImage_MaitrePlan not in photos: + self.monImage_MaitrePlan = str() # Nom de l'image maîtresse du plan repere (sans extension) + self.monImage_PlanTif = str() # nom du masque correspondant + + # Distance + # dicoCalibre key = nom point, photo, identifiant, value = x,y + + if self.dicoCalibre.__len__()>0: + photosAvecDistance = set([(e[1],e) for e in self.dicoCalibre.keys()]) # ensemble des clés et des noms de fichiers + for photo,key in photosAvecDistance: + if not os.path.exists(photo): + del self.dicoCalibre[key] + + + #Points GPS + # dicoPointsGPSEnPlace key = nom point, photo, identifiant, value = x,y + # Suppression des points GPS placés sur des photos non choisies dans le nouveau choix + # l'utilisateur a été prévenu + + if self.dicoPointsGPSEnPlace.__len__()>0: + photosAvecPointsGPS = set([e[1] for e in self.dicoPointsGPSEnPlace.keys()]) + for e in photosAvecPointsGPS: + if e not in photos: + copieDico = dict(self.dicoPointsGPSEnPlace) + for f in copieDico.keys(): + if f[1]==e: + del self.dicoPointsGPSEnPlace[f] + + + # masques et maitresses + + self.listeDesMaitresses = [e for e in self.listeDesMaitresses if e in photos] # liste des images maitresses + self.listeDesMasques = [e for e in self.listeDesMasques if e.replace('_masque.tif',self.extensionChoisie) in photos] # liste Des Masques associès aux maîtresses + + + # suppression du masque 3 d (qui dépend de apericloud.ply) + + supprimeFichier(self.masque3DSansChemin) + supprimeFichier(self.masque3DBisSansChemin) + + # reconstitution des xml + + self.finOptionsOK () # mise à jours des fichiers xml liès aux options + self.miseAJourItem701_703() # met à jour les windgets de l'onglet Malt + + # ------------------ Tawny : aprés Malt, si self.modeMalt.get() = Ortho et self.tawny.get() = Vrai ----------------------- + + def lanceTawny(self): + + if self.modeMalt.get() != "Ortho": + return + if not self.tawny.get(): + return + '''Tawny -help + ***************************** + * Help for Elise Arg main * + ***************************** + Unnamed args : + * string :: {Directory where are the datas} + Named args : + * [Name=DEq] INT :: {Degree of equalization (Def=1)} + * [Name=DEqXY] Pt2di :: {Degree of equalization, if diff in X and Y} + * [Name=AddCste] bool :: {Add unknown constant for equalization (Def=false)} + * [Name=DegRap] INT :: {Degree of rappel to initial values, Def = 0} + * [Name=DegRapXY] Pt2di :: {Degree of rappel to initial values, Def = 0} + * [Name=RGP] bool :: {Rappel glob on physically equalized, Def = true} + * [Name=DynG] REAL :: {Global Dynamic (to correct saturation problems)} + * [Name=ImPrio] string :: {Pattern of image with high prio, def=.*} + * [Name=SzV] INT :: {Sz of Window for equalization (Def=1, means 3x3)} + * [Name=CorThr] REAL :: {Threshold of correlation to validate''' + tawny = [self.mm3d, + "Tawny", + "Ortho-MEC-Malt/", + self.tawnyParam.get(), + "Out="+self.orthoMosaiqueTawny] + self.lanceCommande(tawny, + filtre=self.filtreTawny, + info=_("lance Tawny")) + + def filtreTawny(self,ligne): + if "Don't understand" in ligne: + return ligne + if "FATAL ERROR" in ligne: + return ligne+_(" : voir la trace complète.") + if "KBOX" in ligne: + return ligne # ------------------ C3DC : alternative à Malt avec un masque 3D ----------------------- def lanceC3DC(self): # Si on a un masque 3D on l'utilise et on ne cherche pas plus loin : + self.densification = "C3DC" + # exclusion des images pour la calibration si demandé : + C3DC = [self.mm3d, "C3DC", - "MicMac", + self.modeC3DC.get(), ".*"+self.extensionChoisie, self.orientation(), "Masq3D="+self.masque3DSansChemin, - "Out=modele3D.ply"] + "Out="+self.modele3DEnCours] self.lanceCommande(C3DC, - self.filtreC3DC, - "ATTENTION : cette procédure est longue : patience !") + filtre=self.filtreC3DC, + info=_("ATTENTION : cette procédure est longue : patience !")) def filtreC3DC(self,ligne): if ligne[0]=="|": return ligne if 'BEGIN BLOC' in ligne: return ligne + + # ------------------ NUAGE2PLY ----------------------- - # exemple après GeomImage : C:\MicMac64bits\bin\nuage2ply.exe MM-Malt-Img-P1000556\NuageImProf_STD-MALT_Etape_8.xml Attr=P1000556.JPG Out=modele3D.ply - def lanceNuage2PlyGeom(self): + + # exemple après GeomImage : C:\MicMac64bits\bin\nuage2ply.exe MM-Malt-Img-P1000556\NuageImProf_STD-MALT_Etape_8.xml Attr=P1000556.JPG Out=self.modele3DEnCours + # passe d'un nuage (fichier xml pour une maitresse si geomimage) à un ply, Attr = fichier de drapage. + def tousLesNuages(self): #le zoom est dans self.zoomF.get() et l'étape dans self.etapeNuage : ils sont corrélés comme suit + + # étapes = 1,2,3,4,5,6,7,8 zoom = 128,64,32,16,8,4,2,1 + # zoom : 1,2,4,8,16,32,64,128 étapes = 8,7,6,5,4,3,2,1 + + sauveEtapeNuage = self.etapeNuage + listeModeles = list() + for zoom in [[str(8-j),str(pow(2,j))] for j in range(8-int(self.etapeNuage),8)]: + self.maitreSansExtension = os.path.splitext(self.maitreSansChemin)[0] + + for zoom in [[str(j),str(pow(2,8-j))] for j in range(1,int(sauveEtapeNuage)+1)]: + self.modele3DEnCours = "modele3D_"+self.maitreSansExtension+"_Zoom_"+zoom[1]+".ply" + listeModeles.insert(0,self.modele3DEnCours) # liste triée des modèles, le plus précis en tête + self.etapeNuage = zoom[0] + self.zoomNuage = zoom[1] + self.lanceNuage2Ply() + + self.etapeNuage = sauveEtapeNuage + + # dernier modele ayant été créé : + for e in listeModeles: + if os.path.exists(e): + self.modele3DEnCours = e + return + + + def lanceNuage2Ply(self): # nuage2Ply avec un paramètre : self.etapeNuage, et crée le fichier ply : self.modele3DEnCours + if self.modeMalt.get() in ("GeomImage","AperoDeDenis"): + self.lanceNuage2PlyGeom() + if self.modeMalt.get() in ("UrbanMNE"): + self.lanceNuage2PlyUrban() + if self.modeMalt.get() in ("Ortho"): + self.lanceNuage2PlyOrtho() + + def lanceNuage2PlyGeom(self): + arg1 = 'MM-Malt-Img-'+self.maitreSansExtension+'/NuageImProf_STD-MALT_Etape_'+self.etapeNuage+'.xml' + if os.path.exists(arg1)==False: + return Nuage2Ply = [self.mm3d, "Nuage2Ply", - 'MM-Malt-Img-'+self.nomMaitreSansExtension+'/NuageImProf_STD-MALT_Etape_8.xml', + arg1, 'Attr='+self.maitreSansChemin, - 'Out=modele3D.ply'] + 'Out='+self.modele3DEnCours] self.lanceCommande(Nuage2Ply) - # exemple aprés UrbanMNE : mm3d Nuage2Ply "MEC-Malt/NuageImProf_STD-MALT_Etape_8.xml" Scale=8 Attr="MEC-Malt/Z_Num8_DeZoom1_STD-MALT.tif" Out="modele3D.ply" + # exemple aprés UrbanMNE : mm3d Nuage2Ply "MEC-Malt/NuageImProf_STD-MALT_Etape_8.xml" Scale=8 Attr="MEC-Malt/Z_Num8_DeZoom1_STD-MALT.tif" Out="self.modele3DEnCours" + # si tawny : ajouter l'attribut : def lanceNuage2PlyUrban(self): - Nuage2Ply = [self.mm3d, + if int(self.zoomNuage)>32: # le mode UrbanMNE ne génère apparemment des nuages que pour les zoom de 32 à 1, soit les étapes 3 à 8 + return + arg1 = "MEC-Malt/NuageImProf_STD-MALT_Etape_"+self.etapeNuage+".xml" + if os.path.exists(arg1)==False: + return + + Nuage2Ply = [self.mm3d, "Nuage2Ply", - "MEC-Malt/NuageImProf_STD-MALT_Etape_8.xml", - "Scale=8", - "Attr=MEC-Malt/Z_Num8_DeZoom1_STD-MALT.tif", - 'Out=modele3D.ply'] - self.lanceCommande(Nuage2Ply) - + arg1, + 'Out='+self.modele3DEnCours] + self.lanceCommande(Nuage2Ply) + + def lanceNuage2PlyOrtho(self): + if int(self.zoomNuage)>32: # le mode Ortho ne génère apparemment des nuages que pour les zoom de 32 à 1, soit les étapes 3 à 8 + print("sup32:",self.zoomNuage) + + arg1 = "MEC-Malt/NuageImProf_STD-MALT_Etape_"+self.etapeNuage+".xml" + if os.path.exists(arg1)==False: + return + orthoMosaique = os.path.join(self.repTravail,"Ortho-MEC-Malt",self.orthoMosaiqueTawny) # Orthophotomosaic.tif sous le répertoire "Ortho-MEC-Malt/" + if os.path.exists(orthoMosaique): + Nuage2Ply = [self.mm3d, + "Nuage2Ply", + arg1, + "Attr="+orthoMosaique, # pour draper le ply (l'ortho est créée par Tawny) + 'Out='+self.modele3DEnCours] + else: + Nuage2Ply = [self.mm3d, + "Nuage2Ply", + arg1, + 'Out='+self.modele3DEnCours] + self.lanceCommande(Nuage2Ply) + # ------------------ Meslab 2 -------------------------- - def lanceMeshlab(self): - aOuvrir = os.path.join(self.repTravail,"modele3D.ply") + def ouvreModele3D(self): + + aOuvrir = os.path.join(self.repTravail,self.modele3DEnCours) if not os.path.exists(aOuvrir): - texte="Pas de fichier modele3D.ply généré.\n\nEchec du traitement MICMAC" + texte=_("Pas de fichier %s généré.") % (self.modele3DEnCours)+ "\n\n" + _("Echec du traitement MICMAC") self.ajoutLigne(texte) return -1 if not os.path.exists(self.meshlab): - open_file('AperiCloud.ply') + open_file(self.modele3DEnCours) return meshlab = [self.meshlab, aOuvrir] self.lanceCommande(meshlab, - info="Nuage de points modele3D.ply généré.", + info=_("Nuage de points %s généré.") % (self.modele3DEnCours), attendre=False) - ################################## UTILITAIRES MICMAC ########################################################### + def nettoyerChantier(self): # Le chantier est nettoyé : les résulats sous reptravail sont conservés, les arborescences de calcul effacés + self.etatDuChantier = 2 + self.enregistreChantier() + #retour à l'état initial pour les photos de calibration + if self.calibSeule.get(): + [os.rename(e,os.path.basename(e)) for e in self.photosPourCalibrationIntrinseque] + self.photosPourCalibrationIntrinseque = [os.path.join(self.repTravail,os.path.basename(e)) for e in self.photosPourCalibrationIntrinseque] + self.photosAvecChemin += self.photosPourCalibrationIntrinseque + self.photosSansChemin = [os.path.basename(g) for g in self.photosAvecChemin] + listeAConserver = os.listdir(self.repTravail) + supprimeArborescenceSauf(self.repTravail,listeAConserver) + + ################################## UTILITAIRES MICMAC ########################################################### def OutilQualitePhotosLine(self): - if self.pasDePhoto():return + if self.pasDePhoto():return + if self.pasDeMm3d():return - # on copie les photos dans un répertoire de test + # on copie les photos dans un répertoire de test # - self.copieDansRepertoireDeTest() + self.copieDansRepertoireDeTest("Line") - self.encadre("Détermine un indice de qualité des photos en mode 'line'\n\n"+ - "Le résultat sera inscrit dans le fichier trace synthétique\n\nPatience...",nouveauDepart='non') + self.encadre(_("Détermine un indice de qualité des photos en mode 'line'") + "\n\n"+ + _("Le résultat sera inscrit dans le fichier trace synthétique") + "\n\n" + _("Patience..."),nouveauDepart='non') - self.ajoutLigne(heure()+"Debut de la recherche sur la qualité des photos mode 'Line'.") + self.ajoutLigne(heure()+"\n\n" + _("Debut de la recherche sur la qualité des photos mode 'Line'.")) self.qualiteTrouvee = list() qualite = [self.mm3d, "Tapioca", "Line", ".*"+self.extensionChoisie, #'"'+str(self.repTravail+os.sep+".*"+self.extensionChoisie)+'"', - "1000", - "1"] + self.echelle4.get(), + self.delta.get(), + "ExpTxt="+self.exptxt] self.lanceCommande(qualite, - self.filtreQualite) + filtre=self.filtreQualite) + self.ecritureTraceMicMac() # analyse des résultats : - os.chdir(self.repTravail) - self.analyseQualitePhotos() - self.ajoutLigne("\n"+heure()+" : Fin de la recherche sur la qualité des photos mode 'Line'.") - self.ajoutLigne("\n\n ******") - ligneFiltre = self.ligneFiltre #l'écriture de la trace efface self.ligneFiltre et encadre doit être en fin de paragraphe - self.ecritureTraceMicMac() - self.encadre(ligneFiltre) + self.nombrePointsHomologues(self.repTest) def OutilQualitePhotosAll(self): if self.pasDePhoto():return + if self.pasDeMm3d():return # on copie les photos dans un répertoire de test - self.copieDansRepertoireDeTest() + self.copieDansRepertoireDeTest("All") - self.encadre("Détermine un indice de qualité des photos en mode 'All' ou 'MulScale' \n\n"+ - "Le résultat sera inscrit dans le fichier trace synthétique\n\nPatience...",nouveauDepart='non') + self.encadre(_("Détermine un indice de qualité des photos en mode 'All' ou 'MulScale'") + "\n\n"+ + _("Le résultat sera inscrit dans le fichier trace synthétique") + "\n\n" + _("Patience..."),nouveauDepart='non') - - self.ajoutLigne(heure()+"Debut de la recherche sur la qualité des photos, mode 'All' ou 'MulScale'.") + self.ajoutLigne(heure()+"\n\n" + _("Debut de la recherche sur la qualité des photos, mode 'All' ou 'MulScale'.")) self.qualiteTrouvee = list() qualite = [self.mm3d, "Tapioca", - "All", + "All", ".*"+self.extensionChoisie, - "1000", - "ExpTxt=1"] + self.echelle1.get(), + "ExpTxt="+self.exptxt] self.lanceCommande(qualite, - self.filtreQualite) + filtre=self.filtreQualite) # analyse des résultats : - os.chdir(self.repTravail) # car copieDansRepertoireDeTest a changer le répertoire de travail - - self.analyseQualitePhotos() - - self.ajoutLigne("\n"+heure()+" : Fin de la recherche sur la qualité des photos, mode 'All' ou 'MulScale'.") - self.ajoutLigne("\n\n ******") - ligneFiltre = self.ligneFiltre #l'écriture de la trace efface self.ligneFiltre et encadre doit être en fin de paragraphe - self.ecritureTraceMicMac() - self.encadre(ligneFiltre) + self.ecritureTraceMicMac() + self.nombrePointsHomologues(self.repTest) def filtreQualite(self,ligne): - if 'matches' in ligne: + if 'matches' in ligne: self.encadrePlus("***") self.qualiteTrouvee.append(ligne) return ligne - + return + def analyseQualitePhotos(self): - if self.pasDePhoto():return + if self.pasDePhoto():return + if self.pasDeMm3d():return #somme des scores de chaque photo : homol = dict() nb = dict() @@ -3553,17 +6220,17 @@ def analyseQualitePhotos(self): listeHomol = list(moyenne.items()) listeHomol.sort(key=lambda e: e[1],reverse=True) self.effaceBufferTrace() - self.ajoutLigne("\n ******\n\nClassement des photos par nombre de points homologues :\n\n") + self.ajoutLigne("\n ******\n\n" + _("Classement des photos par nombre de points homologues :") + "\n\n") for e in listeHomol: - self.ajoutLigne("photo "+e[0]+" score = "+str(int(e[1]))+"\n") + self.ajoutLigne(_("photo ")+e[0]+_(" score = ")+str(int(e[1]))+"\n") if len(listeHomol)==0: - self.ajoutLigne("Aucune photo n'a de point analogue avec une autre.\n") + self.ajoutLigne(_("Aucune photo n'a de point analogue avec une autre.") + "\n") def exploiterHomol(self): - self.ajoutLigne("\n ****** Qualité des photos suite au traitement : ") - repHomol = self.repTravail+os.path.sep+'Homol' + self.ajoutLigne("\n ****** " + _("Qualité des photos suite au traitement : ")) + repHomol = self.repTravail+os.path.sep+_('Homol') if os.path.exists(repHomol): lesRep = os.listdir(repHomol) for e in lesRep: @@ -3574,13 +6241,13 @@ def exploiterHomol(self): if os.path.exists(fi): with open(fi) as infile: lignes = infile.readlines() #lecture dicoCamera.xml - print (e,fic,lignes.__len__()) - self.ajoutLigne("\n ****** Fin d'examen de qualité des photos.") - def copieDansRepertoireDeTest(self): + self.ajoutLigne("\n ****** " + _("Fin d'examen de qualité des photos.")) + + def copieDansRepertoireDeTest(self,nom): - self.encadre("Copie des photos dans un répertoire de test.\n Patience...",nouveauDepart='non') - self.repTest = self.repTravail+os.path.sep+"test" + self.encadre(_("Copie des photos dans un répertoire de test.") + "\n" + _("Patience..."),nouveauDepart='non') + self.repTest = self.repTravail+os.path.sep+"test_"+nom if os.path.exists(self.repTest): supprimeArborescenceSauf(self.repTest,os.listdir(self.repTest)) else: @@ -3590,103 +6257,195 @@ def copieDansRepertoireDeTest(self): shutil.copy(e,self.repTest) os.chdir(self.repTest) + ###################### création d'un nouveau chantier avec les meilleurs photos - ###################### Appareil photo : affiche le nom de l'apapreil de la première photo, la focale, la taille du capteur dans dicocamera + def OutilMeilleuresPhotos(self): + self.menageEcran() + repertoireHomol = os.path.join(self.repTravail,"Homol") # répertoire des homologues + if os.path.isdir(repertoireHomol)==False: + self.encadre("Lancer d'abord Tapioca/Tapas") + return + self.item9000.pack() + pass + + def nbMeilleuresOK(self): + nb=self.item9003.get() + liste = [os.path.join(self.repTravail,e) for e in self.lesMeilleuresPhotos(int(nb))] + if self.troisBoutons(titre=_("Nouveau chantier"),question=_("Créer un nouveau chantier avec les photos : ") + +"\n"+"\n"+"\n".join(liste)+" ?\n"+"\n"+_("Les paramètres de Tapioca/Malt seront optimisés."))==0: + self.nouveauChantier() + + # crée le repertoire de travail, copie les photos et renvoit le nombre de fichiers photos "acceptables", + # met à 1 l'état du chantier crée self.photosAvecChemin et self.photosSansChemin + # ATTENTION : Supprime l'arborescence et certains résultats. - def OutilAppareilPhoto(self): + self.nombreDExtensionDifferentes(liste) + self.extensionChoisie = self.lesExtensions[0] + retourExtraire = self.extrairePhotoEtCopier(liste) - if self.pasDePhoto():return - - if os.path.exists(self.exiftool)==False: - texte = "L'outil exiftool n'a pas été trouvé. Traitement impossible.\nIndiquer son chemin (menu paramètrage)." - self.encadre(texte) + if retourExtraire.__class__()=='': # si le retour est un texte alors erreur, probablement création du répertoire impossible + self.encadre (_("Impossible de créer le répertoire de travail.") + "\n" + _("Vérifier les droits en écriture sous le répertoire des photos") + "\n"+str(retourExtraire),nouveauDepart="non") + return + if retourExtraire==0: # extraction et positionne self.repertoireDesPhotos, et les listes de photos avec et sanschemin (photosAvecChemin et photosSansChemin) + self.encadre (_("Aucun JPG, PNG, BMP, TIF, ou GIF sélectionné,") + "\n" + _("le répertoire et les photos restent inchangés.") + "\n",nouveauDepart="non") + return + # paramètres de tapioca : MultiScale 300 * MulScale (Line est disqualifié par la sélection des photos, All est trop lourd) + self.modeTapioca.set('MulScale')# Mode (All, MulScale, Line) + self.echelle2.set('300') + self.echelle3.set('-1') + # Paramètre de Tapas : + self.modeCheckedTapas.set('RadialBasic') # mode par défaut depuis la v 2.23 du 14 mars 2016 + self.arretApresTapas.set(1) # 1 : on arrête le traitement après Tapas, 0 on poursuit + # pas encore suvegardé : + self.etatSauvegarde = "*" # chantier modifié + self.etatDuChantier = 1 + self.afficheEtat() + + def nbMeilleuresKO(self): + self.encadre(_("Abandon"),nouveauDepart="non") + pass + + ##################### expression régulière de la liste des meilleures photos autour d'une image maitresse (on explore le répertoire Homol + + def meilleuresPhotosAutourMaitresse(self,maitresse,nombre): + if nombre==-1: + return + repertoireHomol = os.path.join(self.repTravail,"Homol") # répertoire des homologues + if os.path.isdir(repertoireHomol)==False: + return + listeTaille = list() + os.chdir(repertoireHomol) + for e in os.listdir(): # balaie tous les fichiers contenant les points homologues + if maitresse.upper() in e.upper(): + os.chdir(os.path.join(repertoireHomol,e)) + for f in os.listdir(): + listeTaille.append((f, os.path.getsize(f))) # répertoire, nom du fichier et taille + os.chdir(self.repTravail) + listeTaille.sort(key= lambda e: e[1],reverse=True) # trie la liste des fichiers par taille + # supprime l'extension du fichier (toto1234.JPG.dat ou .txt) et garde les N plus grands + listeCorrigee = [os.path.splitext(e)[0] for e,f in listeTaille[0:nombre] if os.path.exists(os.path.join(self.repTravail,os.path.splitext(e)[0]))] + listeCorrigee.append(maitresse) + return "|".join(listeCorrigee) + + ###################### Stratégie APERODEDENIS pour trouver les maitresses et les images associées. (dépend des noms de répertoire et fichiers donnés par micmac) + # renvoie une liste de tuple : maitresse, liste des photos associées + + def maltApero(self): + # liste des paires de photos et taille + listeTaille = list() + self.maitressesEtPhotoApero = list() + repertoireHomol = os.path.join(self.repTravail,"Homol") # répertoire des homologues + if os.path.exists(repertoireHomol)==False: return + os.chdir(repertoireHomol) + for e in os.listdir(): # balaie tous les fichiers contenant les points homologues + os.chdir(os.path.join(repertoireHomol,e)) + for f in os.listdir(): + listeTaille.append((e.replace("Pastis",""), os.path.splitext(f)[0], os.path.getsize(f))) # répertoire (pastis+nomphoto), nom du fichier(nomphoto+.dat ou .txt) et taille + os.chdir(self.repTravail) + listeTaille.sort(key= lambda e: e[2],reverse=True) # trie la liste des fichiers par taille + listeFixe = list(listeTaille) + # première maitresse = e de la paire la plus importante, associée à f + while listeTaille.__len__(): + e = listeTaille[0][0] + f = listeTaille[0][1] + t = listeTaille[0][2] + self.maitressesEtPhotoApero.append([e,f]) # on ajoute la maitresse et la photo associée + # Suppression de la liste de toutes les paires comportant e ou f + [listeTaille.remove((g,h,i)) for (g,h,i) in listeFixe if (e==g or e==h or f==g or f==h) and (g,h,i) in listeTaille] + self.listeDesMaitressesApero = [e for e,f in self.maitressesEtPhotoApero] # MaltApero renvoit la liste des maîtresses sous forme (maitresse, photo) + + + ###################### Appareil photo : affiche le nom de l'appareil de la première photo, la focale, la taille du capteur dans dicocamera + + def OutilAppareilPhoto(self,silence=None): + if self.pasDePhoto():return + if self.pasDeExiftool():return - texte = " ******\nCaractéristiques de l'appareil photo : \n\n" + texte = " ******\n" + _("Caractéristiques de l'appareil photo : ") + "\n\n" self.fabricant = self.tagExif("Make") if self.fabricant!=str(): - texte = texte + "fabricant : "+self.fabricant+"\n" + texte = texte + _("fabricant : ")+self.fabricant+"\n" self.nomCamera = self.tagExif("Model") if self.nomCamera==str(): - self.encadre ("Nom de l'appareil photo inacessible.") - return + texte = texte+_("Nom de l'appareil photo inacessible.") else: - texte = texte+"Nom de l'appareil photo : "+self.nomCamera+"\n" + texte = texte+_("Nom de l'appareil photo : ")+self.nomCamera+"\n" self.focale35MM = self.tagExif("FocalLengthIn35mmFormat") self.focale = self.tagExif("FocalLength") if self.focale==str(): - texte = texte +("\nPas de focale dans l'exif.") + texte = texte +("\n" + _("Pas de focale dans l'exif.")) else: - texte = texte+"\nFocale : "+ self.focale+"\n" + texte = texte+"\n" + _("Focale : ")+ self.focale+"\n" if self.focale35MM=="" and "35" not in self.focale: - texte = texte +("Pas de focale équivalente 35 mm dans l'exif :\nPrésence de la taille du capteur dans DicoCamera nécesssaire.") + texte = texte +("\n" + _("Pas de focale équivalente 35 mm dans l'exif :") + "\n" + _("Présence de la taille du capteur dans DicoCamera nécesssaire.")) else: if self.focale35MM=="": - texte = texte+"\nFocale équivalente 35 mm absente de l'exif\n" + texte = texte+"\n" + _("Focale équivalente 35 mm absente de l'exif") + "\n" else: - texte = texte+"\nFocale équivalente 35 mm : "+ self.focale35MM+"\n" + texte = texte+"\n" + _("Focale équivalente 35 mm : ")+ self.focale35MM+"\n" if not os.path.isfile(self.CameraXML): - texte = texte+"DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin." + texte = texte+"\n" + _("DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin.") else: self.tailleCapteurAppareil() if self.tailleCapteur==str(): - texte = texte + "\n\nL'appareil est inconnu dans DicoCamera.XML.\n\n" + texte = texte + "\n\n" + _("L'appareil est inconnu dans DicoCamera.XML.") + "\n\n" else: - texte = texte + "\n\nL'appareil est connu dans DicoCamera.XML.\n\n"+\ - "Taille du capteur en mm : \n\n"+self.tailleCapteur+"." + texte = texte + "\n\n" + _("L'appareil est connu dans DicoCamera.XML.") + "\n\n"+\ + _("Taille du capteur en mm : ")+"\n\n"+self.tailleCapteur+"." # écriture du résultat dans le fichier trace et présentation à l'écran self.effaceBufferTrace() - self.ajoutLigne("\n\nAppareil photo :\n"+texte) - self.ecritureTraceMicMac() - self.encadre(texte) + self.ajoutLigne("\n\n" + _("Appareil photo :") + "\n"+texte) + self.ecritureTraceMicMac() + if silence!=None: + return + self.encadre(texte,nouveauDepart='non') # tag dans l'exif : renvoi la valeur du tag 'tag' dans l'exif de la première photo (on suppose qu'elles sont identiques pour toutes les photos) - def tagExif(self,tag): - if os.path.exists(self.exiftool)==False: - texte = "L'outil exiftool n'a pas été trouvé. Traitement impossible.\nIndiquer son chemin (menu paramètrage)." - return texte + def tagExif(self,tag,photo=""): + if photo=="":photo=self.photosAvecChemin[0] self.tag = str() - if self.pasDePhoto():return self.tag - if os.path.exists(self.exiftool): - exif = (self.exiftool, - "-"+tag, - self.photosAvecChemin[0]) - self.lanceCommande(exif, - self.FiltreTag) + exif = [self.exiftool, + "-"+tag, + photo] + self.lanceCommande(exif, + filtre=self.FiltreTag) + self.effaceBufferTrace() return self.tag def FiltreTag(self, ligne): # ne retourne rien (pour éviter la trace, mais positionne si possible self.tag if "can't open" in ligne: - return "Erreur dans exiftool : "+ligne + return _("Erreur dans exiftool : ")+ligne try: self.tag = ligne.split(":")[1].strip() # pour récupérer le nom, et supprimer le retour chariot de fin de ligne - except: pass + except Exception as e: print(_("erreur tagExif : "),str(e)) return None # tags dans l'exif : renvoi la valeur du tag 'tag' dans l'exif de toutes les photos def tagsExif(self,tag): - if os.path.exists(self.exiftool)==False: - texte = "L'outil exiftool n'a pas été trouvé. Traitement impossible.\nIndiquer son chemin (menu paramètrage)." - return texte - + self.tags = list() - if os.path.exists(self.exiftool): - exif = (self.exiftool, - "-"+tag, - os.path.join(self.repTravail,"*"+self.extensionChoisie)) - self.lanceCommande(exif, - self.FiltreTags) + if self.systeme=='nt': + exif = [self.exiftool, + "-"+tag, + os.path.join(self.repTravail,"*"+self.extensionChoisie)] + else: + exif = [self.exiftool, + "-"+tag, + os.path.join(self.repTravail)] + self.lanceCommande(exif, + filtre=self.FiltreTags) return self.tags def FiltreTags(self, ligne): @@ -3725,38 +6484,35 @@ def tailleCapteurAppareil(self): def miseAJourDicoCamera(self): if self.pasDePhoto():return - - if os.path.exists(self.exiftool)==False: - texte = "L'outil exiftool n'a pas été trouvé. Traitement impossible." - self.encadre(texte) - return + if self.pasDeMm3d():return + if self.pasDeExiftool():return self.nomCamera = self.tagExif("Model") if self.nomCamera==str(): - self.encadre("Pas trouvé de nom d'appareil photo dans l'exif.") + self.encadre(_("Pas trouvé de nom d'appareil photo dans l'exif."),nouveauDepart='non') return if not os.path.isfile(self.CameraXML): - self.encadre("DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin.") + self.encadre(_("DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin."),nouveauDepart='non') return if self.tailleCapteurAppareil()==1: - self.encadre( "Le fichier DicoCamera.xml contient la taille du capteur pour l'appareil :\n\n"+ - self.nomCamera+"\n\ntaille = "+self.tailleCapteur+ - "\n\nModification non prévue dans cette version de l'outil AperoDeDenis\n----------------") + self.encadre( _("Le fichier DicoCamera.xml contient la taille du capteur pour l'appareil :") + "\n\n"+ + self.nomCamera+"\n\n" + _("taille = ")+self.tailleCapteur+ + "\n\n" + _("Modification non prévue dans cette version de l'outil AperoDeDenis") + "\n----------------",nouveauDepart='non') return self.menageEcran() - self.item1001.configure(text="Pour l'appareil "+self.nomCamera) + self.item1001.configure(text=_("Pour l'appareil ")+self.nomCamera) self.item1000.pack() def dimensionCapteurOK(self): if not os.path.isfile(self.CameraXML): - self.encadre("Paramètrer au préalable le chemin de MicMac\\bin.") + self.encadre(_("Paramètrer au préalable le chemin de MicMac\\bin."),nouveauDepart='non') return dimension = self.item1003.get() # paragraphe à rajouter à DicoCamera : texte - texte = self.dicoCameraXMLTaille.replace("NomCourt",self.nomCamera) - texte = texte.replace("Nom",self.nomCamera) - texte = texte.replace("tailleEnMM",dimension) + texte = self.dicoCameraXMLTaille.replace(_("NomCourt"),self.nomCamera) + texte = texte.replace(_("Nom"),self.nomCamera) + texte = texte.replace(_("tailleEnMM"),dimension) #lecture dicocamera.xml : with open(self.CameraXML) as infile: @@ -3770,238 +6526,489 @@ def dimensionCapteurOK(self): try: with open(self.CameraXML,mode="w") as outfile: outfile.write(newDico) - except: - self.encadre("Erreur lors de l'écriture de DicoCamera.xml\nUne sauvegarde a été créée : DicoCamerra.xml.sav") + except:#ici + self.encadre(_("Erreur lors de l'écriture de DicoCamera.xml") + "\n" + _("Une sauvegarde a été créée : DicoCamerra.xml.sav"),nouveauDepart='non') + return + else: + self.encadre(_("Dimensions du capteur non mis à jour") + "\n",nouveauDepart='non') + return + + self.encadre(_("Dimensions du capteur mis à jour") + "\n"+texte,nouveauDepart='non') + + + def dimensionCapteurKO(self): + self.encadre(_("Dimensions du capteur non mis à jour"),nouveauDepart='non') + + def toutesLesFocales(self): + + if self.pasDePhoto():return + if self.pasDeExiftool():return + + texte=self.tagsExif("FocalLength") + texte=texte+["\n",]+self.tagsExif("FocalLengthIn35mmFormat") + self.effaceBufferTrace() + self.ajoutLigne(" ****** \n" + _("Toutes les focales : ") + "\n\n"+"".join(texte)+"\n ****** \n") + self.ecritureTraceMicMac() + self.encadre(texte,nouveauDepart='non') + + ################################## le menu Expert + + def lignesExpert(self): + self.ecritureTraceMicMac() + self.cadreVide() # ménage écran, ouverture trace + texte = _("Saisir une ou plusieurs ligne(s) de commande") + "\n" + if self.etatDuChantier==0: + texte+="\n\n"+_("Attention : Le chantier n'existe pas.") + + bas = ( + _("Entrer soit une commande MicMac, par exemple : mm3d GCPBascule .*.JPG Arbitrary")+"\n\n"+ + _("S'il n'y a pas de path sur mm3d entrer le chemin : ")+afficheChemin(self.micMac)+"\n\n"+ + _("soit une commande du système, par exemple sous windows : del /S /Q Tmp-MM-Dir")+"\n\n"+ + _("Sous votre responsabilité")) + new = MyDialogTexte(fenetre,texte,basDePage=bas,boutonDialogueTexteOk="Exécuter") + if new.saisie=="": + return + lignes = new.saisie.split("\n") + for ligne in lignes: + if ligne: + self.lanceCommande(ligne.split()) + os.chdir(self.repTravail) # on ne sait pas ce qu'a fait l'utilisateur + self.encadre(self.lignePourTrace,nouveauDepart="non") + self.ecritureTraceMicMac() + + def ajoutPointsGPSAutreChantier(self): + + self.menageEcran() + bilan = self.choisirUnChantier(_("Choisir le chantier pour ajouter les points gps.")) # boite de dialogue de sélection du chantier à ouvrir, renvoi : self.selectionRepertoireAvecChemin + if bilan!=None: + self.afficheEtat(_("Aucun chantier choisi.") + "\n" + bilan + "\n") + return + fichierParamChantierAutre = os.path.join(self.selectionRepertoireAvecChemin,self.paramChantierSav) + if os.path.exists(fichierParamChantierAutre): + try: # s'il y a une sauvegarde alors on la restaure + sauvegarde1=open(fichierParamChantierAutre,mode='rb') + r=pickle.load(sauvegarde1) + sauvegarde1.close() + listePointsGPS = r[12] + dicoPointsGPSEnPlace = r[20] + idPointGPS = r[23] + + # pour assurer la compatibilité ascendante suite à l'ajout de l'incertitude dans la description des points GPS + # passage vers la version 2.60 de la liste des points GPS (un item de plus dans le tuple) + + if listePointsGPS.__len__()>0: + if listePointsGPS[0].__len__()==6: + listePointsGPS = [[a,nom,x,y,z,ident,"10 10 10"] for a,nom,x,y,z,ident in listePointsGPS] + except Exception as e: + self.encadre (_('Chantier choisi %s corrompu. Abandon.') % (self.selectionRepertoireAvecChemin),nouveauDepart='non') + print(_("Erreur restauration points GPS : "),str(e)) return else: - self.encadre("Dimensions du capteur non mis à jour\n") + self.encadre (_('Chantier choisi %s corrompu. Abandon.') % (self.selectionRepertoireAvecChemin),nouveauDepart='non') return + + # 3 variables : self.dicoPointsGPSEnPlace, self.listePointsGPS et self.idPointGPS pour le chantier en cours et idem (sans self.) pour le chantier a ajouter + # dicoPointsGPSEnPlace key = nom du point, photo, identifiant, value = x,y + # listePointsGPS : 7-tuples (nom du point, x, y et z gps, booléen actif, identifiant,incertitude) + # idPointGPS : entier, identifiant du dernier point GPS + + # 1) Modifier la clé du dico lu : chemin de la photo et identifiant par ajout de la valeur de self.idPointGPS + # si la photo existe alors ajout dans le dico du chantier en cours + + for nom,photo,identifiant in dicoPointsGPSEnPlace.keys(): + nouvelId = identifiant + self.idPointGPS + nouveauNom = nom + "_" + str(nouvelId) + nouvellePhoto = os.path.join(self.repTravail,os.path.basename(afficheChemin(photo))) + + if os.path.exists(nouvellePhoto): + self.dicoPointsGPSEnPlace[nouveauNom,nouvellePhoto,nouvelId] = dicoPointsGPSEnPlace[nom,photo,identifiant] # la photo existe, on ajoute au dico des points en place l'identifiant change + - self.encadre("Dimensions du capteur mis à jour\n"+texte) + # 2) Modifier la liste des points GPS : identifiant pat ajout de la valeur de self.idPointGPS, éviter les noms en double + for nom,b,c,d,e,identifiant,g in listePointsGPS: + nouvelId = identifiant + self.idPointGPS + nouveauNom = nom + "_"+ str(nouvelId) + self.listePointsGPS.append([nouveauNom,b,c,d,e,nouvelId,g]) - def dimensionCapteurKO(self): - self.encadre("Dimensions du capteur non mis à jour") + # 3) Trouver la nouvelle valeur de self.idPointGPS + + self.idPointGPS = 1 + max ([f for a,b,c,d,e,f,g in self.listePointsGPS]) - def toutesLesFocales(self): + # mise à jour de la liste des widgets pour saisie : - if self.pasDePhoto():return - - if os.path.exists(self.exiftool)==False: - texte = "L'outil exiftool n'a pas été trouvé. Traitement impossible." - self.encadre(texte) - return - - texte=self.tagsExif("FocalLength") - texte=texte+["\n",]+self.tagsExif("FocalLengthIn35mmFormat") - self.effaceBufferTrace() - self.ajoutLigne(" ****** \nToutes les focales : \n\n"+"".join(texte)+"\n ****** \n") - self.ecritureTraceMicMac() - self.encadre(texte) + self.optionsReperes() + + # Affichage de l'état du chantieravec les nouveaux points GPS + + self.afficheEtat() + ################################## Le menu AIDE ########################################################### # provisoirement retirés : #" Afficher les photos après nettoyage : visualise les photos après nettoyage\n" #" - Nettoyer les photos : permet de délimiter les zones ""utiles"" des photos.\n" #" Cette option n'est pas active dans la version 1.0 de l'outil.\n" def aide(self): - aide1= "Interface graphique pour lancer les modules de MICMAC.\n\n"+\ - "Utilisable sous Linux, Windows, Mac OS.\n"+\ - "Logiciel libre diffusé sous licence CeCILL-B.\n"+\ + aide1 = _("Interface graphique pour lancer les modules de MICMAC.") + "\n\n"+\ + _("Utilisable sous Linux, Windows, Mac OS.") + "\n"+\ + _("Logiciel libre diffusé sous licence CeCILL-B.") + "\n"+\ "-----------------------------------------------------------------------------------------------------------------\n\n"+\ - "La barre de titre présente le nom du chantier et la version de l'outil. Une * indique que le chantier est à sauvegarder.\n\n"+\ - "Menu Fichier :\n\n"+\ - " - Nouveau chantier : constitution d'un 'chantier' comportant les photos, les options d'exécution de Micmac et\n"+\ - " les résultats des traitements.\n"+\ - " Les paramètres du chantier sont conservés dans le fichier "+self.paramChantierSav+".\n"+\ - " Enregistrer le chantier crée une arborescence dont la racine est le répertoire des photos et le nom du chantier.\n\n"+\ - " - Ouvrir un chantier : revenir sur un ancien chantier pour le poursuivre ou consulter les résultats.\n\n"+\ - " - Enregistrer le chantier : enregistre le chantier en cours sans l'exécuter.\n"+\ - " Une * dans la barre de titre indique que le chantier a été modifié.\n"+\ - " Le chantier en cours, même non enregistré, est conservé lors de la fermeture de l'application.\n\n"+\ - " - Renommer le chantier : personnalise le nom du chantier.\n\n"+\ - " Le chantier est déplacé dans l'arborescence en indiquant un chemin absolu ou relatif.\n"+\ - " Par exemple : 'D:\\MonPremierChantier' nomme 'MonPremierChantier' sous la racine du disque D.\n"+\ - " Attention : le changement de disque n'est pas possible dans cette version de l'outil.\n\n"+\ - " - Du ménage ! : Supprimer les chantiers : Chaque chantier crée une arborescence de travail.\n"+\ - " Cet item permet de supprimer les répertoires devenu inutiles.\n"+\ - " Aprés un message demandant confirmation la suppression est définitive, sans récupération possible.\n\n"+\ - " - Quitter : quitte l'application, le chantier en cours est conservé et sera ouvert lors de la prochaine exécution.\n\n"+\ - "Menu Edition :\n\n"+\ - " - Afficher l'état du chantier : affiche les paramètres du chantier et son état d'exécution.\n"+\ - " Par défaut l'état du chantier est affiché lors du lancement de l'application.\n"+\ - " Cet item est utile après un message ou l'affichage d'une trace.\n\n"+\ - " - Plusieurs items permettent de consulter les photos, les traces et les vues 3D du chantier en cours.\n\n"+\ - " Visualiser toutes les photos sélectionnées : visualise les photos\n"+\ - " Visualiser les points GPS : visu des seules photos avec points GPS.\n"+\ - " Visualiser le masque 3D : visualise le masque 3D\n"+\ - " Visualiser le masque 2D et l'image maitre : visualise le masque 2D s'il existe et de l'image maître.\n"+\ - " Visualiser la ligne horizontale/verticale : visualise le repère Ox ou Oy.\n"+\ - " Visualiser la zone plane : visualise la zone plane\n"+\ - " Visualiser la distance : visualise de la distance et les points associés.\n"+\ + _("La barre de titre présente le nom du chantier et la version de l'outil. Une * indique que le chantier est à sauvegarder.") + "\n\n"+\ + _("Menu Fichier :") + "\n\n"+\ + _(" - Nouveau chantier : constitution d'un 'chantier' comportant les photos, les options d'exécution de Micmac et") + "\n"+\ + _(" les résultats des traitements.") +"\n"+\ + _(" Les paramètres du chantier sont conservés dans le fichier ")+self.paramChantierSav+".\n"+\ + _(" Enregistrer le chantier crée une arborescence dont la racine est le répertoire des photos et le nom du chantier.") + "\n\n"+\ + _(" - Ouvrir un chantier : revenir sur un ancien chantier pour le poursuivre ou consulter les résultats.") + "\n\n"+\ + _(" - Enregistrer le chantier : enregistre le chantier en cours sans l'exécuter.") + "\n"+\ + _(" Une * dans la barre de titre indique que le chantier a été modifié.") + "\n"+\ + _(" Le chantier en cours, même non enregistré, est conservé lors de la fermeture de l'application.") + "\n\n"+\ + _(" - Renommer le chantier : personnalise le nom du chantier.") + "\n\n"+\ + _(" Le chantier est déplacé dans l'arborescence en indiquant un chemin absolu ou relatif.") + "\n"+\ + _(" Par exemple : 'D:\\MonPremierChantier' nomme 'MonPremierChantier' sous la racine du disque D.") + "\n"+\ + _(" Attention : le changement de disque n'est pas possible dans cette version de l'outil.") + "\n\n"+\ + _(" - Exporter le chantier en cours : création d'une archive du chantier, qui permet :") + "\n"+\ + _(" - de conserver le chantier en l'état, pour y revenir.") + "\n"+\ + _(" - de l'importer sous un autre répertoire, un autre disque, un autre ordinateur, un autre système d'exploitation") + "\n\n"+\ + _(" - Importer un chantier :") + "\n"+\ + _(" - copie le chantier sauvegardé dans un nouvel environnement (ordinateur, système d'exploitation)") + "\n"+\ + _(" - un exemple d'intérêt : copier un chantier aprés tapas, lancer malt avec des options variées sans perdre l'original.") + "\n\n"+\ + _(" - Du ménage ! : supprimer les chantiers : chaque chantier crée une arborescence de travail.") + "\n"+\ + _(" Cet item permet de supprimer les répertoires devenus inutiles.") + "\n"+\ + _(" Aprés un message demandant confirmation la suppression est définitive, sans récupération possible :") + "\n"+\ + _(" toute l'arborescence est supprimée, même les archives exportées.") + "\n\n"+\ + _(" - Quitter : quitte l'application, le chantier en cours est conservé et sera ouvert lors de la prochaine exécution.") + "\n\n"+\ + _("Menu Edition :") + "\n\n"+\ + _(" - Afficher l'état du chantier : affiche les paramètres du chantier et son état d'exécution.") + "\n"+\ + _(" Par défaut l'état du chantier est affiché lors du lancement de l'application.") + "\n"+\ + _(" Cet item est utile après un message ou l'affichage d'une trace.") + "\n\n"+\ + _(" - Plusieurs items permettent de consulter les photos, les traces et les vues 3D du chantier en cours.") + "\n\n"+\ + _(" Visualiser toutes les photos sélectionnées : visualise les photos") + "\n"+\ + _(" Visualiser les points GPS : visu des seules photos avec points GPS.") + "\n"+\ + _(" Visualiser le masque 3D : visualise le masque 3D") + "\n"+\ + _(" Visualiser le masque 2D et l'image maitre : visualise le masque 2D s'il existe et de l'image maître.") + "\n"+\ + _(" Visualiser la ligne horizontale/verticale : visualise le repère Ox ou Oy.") + "\n"+\ + _(" Visualiser la zone plane : visualise la zone plane") + "\n"+\ + _(" Visualiser la distance : visualise de la distance et les points associés.") + "\n"+\ + "\n"+\ + _(" Afficher la trace complete du chantier : visualise la trace complète, standard micmac") + "\n"+\ + _(" Afficher la trace synthétique du chantier : visualise la trace filtrée par aperoDeDenis, moins bavarde") + "\n\n"+\ "\n"+\ - " Afficher la trace complete du chantier : visualise la trace complète, standard micmac\n"+\ - " Afficher la trace synthétique du chantier : visualise la trace filtrée par aperoDeDenis, moins bavarde\n"+\ - " Afficher l'image 3D aprés Tapas : lance l'outil pour ouvrir les .PLY sur l'image 3D produite par Tapas\n"+\ - " Afficher l'image 3D aprés Malt : visualise l'image densifiée produite par Malt.\n\n"+\ - "Menu MicMac :\n\n"+\ - " - Choisir les photos : permet choisir les photos JPG pour le traitement.\n\n"+\ - " Remarque : les JPG doivent comporter un EXIF avec la focale utilisée pour la prise de vue..\n"+\ - " Consulter la documentation MicMac concernant les photos utilisables et le fichier DicoCamera.xml.\n\n"+\ - " - Options : choisir les options des modules Tapioca, Tapas (nuage non densifié) puis de Malt (nuage densifié) : \n\n"+\ - " Les 3 options suivantes concernent le calcul du nuage de points NON densifié :\n\n"+\ - " - Tapioca : options et sous options associées (échelles, fichier xml)\n"+\ - " - Tapas : Choix d'un mode de calcul, possibilité d'arrêter le traitement après tapas.\n"+\ - " L'arrêt après Tapas est nécessaire pour décrire le masque 3D de C3DCla.\n"+\ - " Produit une image 3D avec position des appareils photos.\n"+\ - " - Calibration : définir un axe, une zone plane, une distance pour définir le repère du chantier.\n\n"+\ - " Les 3 options suivantes concernent le calcul du nuage de points densifié :\n\n"+\ - " - Malt : choix du mode, désigner une image maitresse et dessiner le masque associé.\n"+\ - " Seuls les points visibles sur l'image maitre seront sur l'image 3D finale.\n"+\ - " Le masque limite la zone ""utile"" de l'image 3D finale.\n"+\ - " La molette permet de zoomer et le clic droit maintenu de déplacer l'image.\n"+\ - " Choisir une image maitresse réinitialise le masque.\n\n"+\ - " - C3DC : dessiner le masque 3D sur le nuage de points AperiCloud généré par Tapas..\n"+\ - " Les touches fonctions à utiliser sont décrites dans l'onglet.\n"+\ - " Le masque limite la zone en 3 dimensions de l'image finale.\n"+\ - " L'outil de saisie est issu de micmac.\n\n"+\ - " - GPS : Définir les points de calage GPS qui permettent de géolocaliser la scène.\n"+\ - " Pour être utilisé chaque point doit être placé sur au moins 2 photos.\n\n"+\ - " - Lancer MicMac : Enregistre le chantier et lance le traitement avec les options par défaut ou choisies par l'item 'options'.\n"+\ - " Relance micmac si l'arrêt a été demandé après tapas.\n"+\ - " Lancer micmac bloque les photos et les options du chantier.\n"+\ - " Pour débloquer le chantier il faut lancer micmac à nouveau et choisir le débloquage.\n\n"+\ - "menu Outils :\n\n"+\ - " - Nom et focale de l'appareil photo : fabricant, modéle et focale de la première photo.\n"+\ - " Il y a 2 types de focales : focale effective et focale équivalente 35 mm.\n"+\ - " Indique si l'appareil photo est connu dans '/XML MicMac/DicoCamera.xml' (uniquement dans ce fichier).\n"+\ - " - Toutes les focales des photos : focales et focales equivalentes en 35mm.\n"+\ - " Les focales doivent être identiques pour toutes les photos : si besoin créer plusieurs chantiers.\n"+\ - " - Mettre à jour DicoCamera.xml : ajouter la taille du capteur dans '/XML MicMac/DicoCamera.xml'.\n\n"+\ - " La taille du capteur dans DicoCamera.xml est requise si la focale équivalente 35mm est absente de l'exif.\n\n"+\ - " La taille du capteur facilite les calculs et améliore les résultats.\n\n"+\ - " - Qualité des photos 'Line' : calcule le nombre moyen de points homologues par photo en mode 'Line'.\n"+\ - " - Qualité des photos 'MulScale ou All' : calcule le nombre moyen de points homologues par photo.'.\n"+\ - " Ce nombre informe sur la qualité relative des photos au sein du chantier.\n"+\ - " La présence de photos avec peu de points homologues peu faire échouer le traitement.\n"+\ - " Il est préférable de traiter peu de photos mais de bonne qualité.\n\n"+\ - "menu Paramètrage :\n\n"+\ - " - Affiche les paramètres : visualise les chemins de micmac\\bin, d'exiftool et du fichier Meshlab ou Cloud Compare.\n"+\ - " Ces paramètres sont sauvegardés de façon permanente dans le fichier "+self.fichierParamMicmac+".\n\n"+\ - " - Désigner le répertoire MicMac\\bin : répertoire où se trouvent les modules de MicMac \n"+\ - " - Désigner l'application exiftool.\n"+\ - " - Désigner l'application ouvrant les .PLY. Ce peut être Meshlab, Cloud Compare ou autre.\n\n"+\ - " Sous Windows Meshlab se trouve sous un répertoire nommé VCG.\n\n"+\ - "menu Aide :\n\n"+\ - " - Aide \n"+\ - " - Quelques conseils : sur la prise de vue et les paramètres.\n"+\ - " - A propos\n\n\n"+\ - " Quelques précisions :\n"+\ - " Cette version a été développée sous Windows XP et Seven avec micmac rev 1963, puis rev 5508 d'avril 2015.\n"+\ - " L'utilisation d'autres versions de Micmac peut poser problème.\n"+\ - " Cette version n'admet que des photos au format JPG.\n"+\ - " L'outil libre XNView propose des conversions 'sans perte' à partir de multiples formats (via Imagemagick).\n\n"+\ - " Consulter la documentation de MicMac, outil réalisé par l'IGN.\n\n"+\ - " Consulter le guide d'installation et de prise en main d'AperoDeDenis.\n\n"+\ + _(" Afficher l'image 3D non densifiée : lance l'outil pour ouvrir les .PLY sur l'image 3D produite par Tapas") + "\n"+\ + _(" Afficher l'image 3D densifiée : lance l'outil pour ouvrir les .PLY sur l'image 3D produite par Malt ou C3DC") + "\n"+\ + "\n"+\ + _(" Lister Visualiser les images 3D : liste la pyramide des images 3D, créées à chaque étape de Malt") + "\n"+\ + _(" Fusionner des images 3D : permet de fusionner plusieurs PLY en un seul") + "\n\n"+\ + _("Menu MicMac :") + "\n\n"+\ + _(" - Choisir les photos : permet choisir les photos JPG, GIF, TIF ou BMP pour le traitement.") + "\n\n"+\ + _(" Remarque : les photos GIF et BMP seront converties en JPG (nécessite la présence de l'outil convert).") + "\n"+\ + _(" Un EXIF avec la focale utilisée pour la prise de vue est nécessaire : si besoin l'ajouter (menu Outil/ajout exif).") + "\n"+\ + _(" Remarque : ")+ "\n"+\ + _(" Le fichier DicoCamera.xml doit comporter la taille du capteur de l'appareil (voir menu Outils)") + "\n\n"+\ + _(" - Options : choisir les options des modules Tapioca, Tapas (nuage non densifié) puis de Malt (nuage densifié) : ") + "\n\n"+\ + _(" Les options suivantes concernent le calcul du nuage de points NON densifié :") + "\n\n"+\ + _(" - Tapioca : options et sous options associées (échelles, fichier xml)")+ "\n"+\ + _(" - Tapas : choix d'un mode de calcul, possibilité d'arrêter le traitement après tapas.") + "\n"+\ + _(" La calibration intrinsèque permet de lancer Tapas sur un premier lot de photos.") + "\n"+\ + _(" Typiquement sur les photos de plus grande focale si il y a 2 focales différentes.")+ "\n"+\ + _(" L'arrêt après Tapas est nécessaire pour décrire le masque 2D ou 3D.") + "\n"+\ + _(" Produit une image 3D non densifiée avec position des appareils photos.") + "\n"+\ + _(" - Calibration : définir un axe, une zone plane, une distance pour définir le repère du chantier.") + "\n\n"+\ + _(" - GPS : définir les points de calage GPS qui permettent de géolocaliser la scène.") + "\n\n"+\ + _(" Pour être utilisé chaque point, minimum 3, doit être placé sur au moins 2 photos.") + "\n\n"+\ + _(" Cette option est utilisée pour le nuage de point non densifié ET pour le nuage densifié.") + "\n\n"+\ + _(" Les 3 options suivantes concernent le calcul du nuage de points densifié :") + "\n\n"+\ + _(" - Malt : choix du mode et du niveau de densification.") + "\n"+\ + _(" Si le mode est GeomImage : ") + "\n"+\ + _(" désigner une ou plusieurs images maîtresses") + "\n"+\ + _(" dessiner si besoin le ou les masques associés.") + "\n"+\ + _(" Seuls les points visibles sur les images maitres seront sur l'image 3D finale.") + "\n"+\ + _(" Le masque limite la zone utile de l'image 3D finale.") + "\n"+\ + _(" La molette permet de zoomer et le clic droit maintenu de déplacer l'image.") + "\n"+\ + _(" Supprimer une image maîtresse de la liste réinitialise le masque.") + "\n\n"+\ + _(" Nombre de photos utiles autour de l'image maîtresse :") + "\n"+\ + _(" Permet de limiter les recherches aux images entourant chaque image maîtresse.") + "\n\n"+\ + _(" Choix du niveau de densification final : 8,4,2 ou 1.") + "\n"+\ + _(" Le niveau 1 est le plus dense. ") + "\n"+\ + _(" La géométrie est revue à chaque niveau et de plus en plus précise : ") + "\n"+\ + _(" la densification s'accroît, et la géométrie s'affine aussi.") + "\n\n"+\ + _(" - C3DC : dessiner le masque 3D sur le nuage de points AperiCloud généré par Tapas..") + "\n"+\ + _(" Les touches fonctions à utiliser sont décrites dans l'onglet.") + "\n"+\ + _(" Le masque limite la zone en 3 dimensions de l'image finale.") + "\n"+\ + _(" L'outil de saisie est issu de micmac.") + "\n\n"+\ + _(" - GPS : définir les points de calage GPS qui permettent de géolocaliser la scène.") + "\n"+\ + _(" Pour être utilisé chaque point, minimum 3, doit être placé sur au moins 2 photos.") + "\n\n"+\ + _(" Le bouton 'appliquer' permet de calibrer le modèle non densifié immédiatement.") + "\n\n"+\ + _(" - Lancer MicMac : enregistre le chantier et lance le traitement avec les options par défaut ou choisies par l'item 'options'.") + "\n"+\ + _(" Relance micmac si l'arrêt a été demandé après tapas.") + "\n"+\ + _(" Lancer micmac bloque les photos et les options du chantier.") + "\n"+\ + _(" Pour débloquer le chantier il faut lancer micmac à nouveau et choisir le débloquage.") + "\n"+\ + _(" Le débloquage permet de relancer Malt sans relancer tapioca/tapas : ") + "\n"+\ + _(" le fichier modele3D.ply est conservé sous un autre nom.") + "\n\n"+\ + _("menu Vidéo :") + "\n\n"+\ + _(" - Options : indiquer le nom de la camera (GoPro, smartphone...), sa focale, sa focale equivalente 35mm") + "\n"+\ + _(" et le nombre d'images à conserver par seconde de film") + "\n"+\ + _(" Le nom permet de faire le lien avec DicoCamera.xml qui contient la taille du capteur.") + "\n"+\ + _(" Les focales seront recopiées dans l'exif des images.") + "\n"+\ + _(" Le nombre d'images par seconde sera utilisé pour la sélection des meilleures images.") + "\n\n"+\ + _(" Remarque :") + "\n"+\ + _(" Il faut indiquer dans DicoCamera la taille du capteur effectivement utilisée par la fonction camera,") + "\n"+\ + _(" taille qui peut être inférieure à la taille du capteur utilisée pour les photos.") + "\n"+\ + _(" Voir par exemple pour une camera Gopro :") + "\n"+\ + " http://www.kolor.com/wiki-en/action/view/Autopano_Video_-_Focal_length_and_field_of_view#About_GoPro_focal_length_and_FOV" + "\n\n"+\ + _(" - Nouveau chantier : choisir une video : choisir un fichier video issu d'une camera ou d'une GoPro.") + "\n"+\ + _(" La vidéo sera décompactée en images, l'exif sera créé avec les informations en options.") + "\n"+\ + _(" Cette étape nécessite la présence de l'outil ffmpeg sous le répertoire bin de MicMac (dépend de la version de MicMac).") + "\n"+\ + _(" Un nouveau chantier est créé avec les options suivante : Line pour Tapioca et FishEyeBasic pour Tapas.") + "\n\n"+\ + _(" - Sélection des images : il est raisonnable de ne garder que quelques images par seconde de film.") + "\n"+\ + _(" Le nombre d'images conservées par seconde est indiqué dans les options.") + "\n"+\ + _(" Chaque seconde de film les 'meilleures' images seront retenues, les autres effacées.") + "\n"+\ + _(" Attention : cette étape n'est pas effective pour toutes les versions de MicMac. La version mercurial 5508 fonctionne.") + "\n\n"+\ + _(" Une fois les images sélectionnées le chantier est créé : utiliser le menu MicMac comme pour un chantier normal.") + "\n\n"+\ + _("menu Outils :") + "\n\n"+\ + _(" - Affiche le nom et la focale de l'appareil photo : fabricant, modèle et focale de la première photo.") + "\n"+\ + _(" Il y a 2 types de focales : focale effective et focale équivalente 35 mm.") + "\n"+\ + _(" Indique si l'appareil photo est connu dans '/XML MicMac/DicoCamera.xml'.") + "\n\n"+\ + _(" - Affiche toutes les focales des photos : focales et focales equivalentes en 35mm.") + "\n"+\ + _(" Si les focales ne sont pas identiques pour toutes les photos : utiliser la calibration intrinséque de tapas.") + "\n\n"+\ + _(" - Mettre à jour DicoCamera.xml : ajouter la taille du capteur dans '/XML MicMac/DicoCamera.xml'.") + "\n"+\ + _(" La taille du capteur dans DicoCamera.xml est requise si la focale équivalente 35mm est absente de l'exif.") + "\n"+\ + _(" La taille du capteur facilite les calculs et améliore les résultats.") + "\n"+\ + _(" La taille du capteur se trouve sur le site du fabricant ou sur http://www.dpreview.com.") + "\n\n"+\ + _(" - Qualité des photos du dernier traitement : calcule le nombre moyen de points homologues par photo.") + "\n"+\ + _(" Si des photos présentent des moyennes très faibles elles peuvent faire échouer le traitement.") + "\n\n"+\ + _(" - Qualité des photos 'Line' : calcule le nombre moyen de points homologues par photo en mode 'Line', taille 1000.") + "\n\n"+\ + _(" - Qualité des photos 'MulScale ou All' : calcule le nombre moyen de points homologues par photo, taille 1000.'.") + "\n"+\ + _(" Ce nombre informe sur la qualité relative des photos au sein du chantier.") + "\n"+\ + _(" La présence de photos avec peu de points homologues peut faire échouer le traitement.") + "\n"+\ + _(" Il est parfois préférable de traiter peu de photos mais de bonne qualité.") + "\n\n"+\ + _(" - Modifier l'exif des photos : permet la création et la modification des exifs des photos du chantier.") + "\n\n"+\ + _("menu Paramétrage :") + "\n\n"+\ + _(" - Affiche les paramètres : visualise les chemins de micmac\\bin, d'exiftool, du fichier pour visualiser les .ply (Meshlab ou Cloud Compare),") + "\n"+\ + _(" ainsi que le répertoire où se trouve les fichiers paramètres de l'interface.") + "\n"+\ + _(" Ces paramètres sont sauvegardés de façon permanente dans le fichier :")+\ + " "+self.fichierParamMicmac+"." + "\n\n"+\ + _(" - Désigner le répertoire MicMac\\bin : répertoire où se trouvent les modules de MicMac ") + "\n"+\ + _(" Si plusieurs versions sont installées cet item permet de changer facilement la version de MicMac utilisée.") + "\n\n"+\ + _(" - Désigner l'application exiftool, utile pour modifier les exif (elle se trouve sous micMac\\binaire-aux).") + "\n\n"+\ + _(" - Désigner l'application convert d'ImageMagick, utile pour convertir les gif, tif et bmp en jpg (elle se trouve sous micMac\\binaire-aux).") + "\n\n"+\ + _(" - Désigner l'application ouvrant les fichiers .PLY. Ce peut être Meshlab, CloudCompare ou autre.") + "\n"+\ + _(" Sous Windows Meshlab se trouve sous un répertoire nommé VCG.") + "\n\n"+\ + _(" - Activer/désactiver le 'tacky' message de lancement")+ "\n"+\ + _("menu Aide :") + "\n\n"+\ + _(" - Pour commencer : à lire lors de la prise en main de l'interface.") + "\n\n"+\ + _(" - Aide : le détail des items de menu.") + "\n\n"+\ + _(" - Quelques conseils : sur la prise de vue et les options.") + "\n"+\ + _(" - Historique : les nouveautés de chaque version.") + "\n\n"+\ + _(" - A propos") + "\n\n\n"+\ + _(" Quelques précisions :") + "\n"+\ + _(" Cette version a été développée sous Windows XP et Seven avec micmac rev 5508 d'avril 2015.") + "\n"+\ + _(" L'utilisation d'autres versions de Micmac a été testée, jusqu'à la version 6219.") + "\n\n"+\ + _(" Le fonctionnement sous Ubuntu Trusty a été vérifié.") + "\n\n"+\ + _(" Consulter la documentation de MicMac, outil réalisé par l'IGN.") + "\n\n"+\ + _(" Consulter le guide d'installation et de prise en main d'AperoDeDenis.") + "\n\n"+\ "--------------------------------------------- "+self.titreFenetre+" ---------------------------------------------" self.cadreVide() + self.effaceBufferTrace() self.ajoutLigne(aide1) self.texte201.see("1.1") def conseils(self): - aide2= "Interface graphique pour lancer les modules de MICMAC : quelques conseils.\n\n"+\ - "Prises de vue :\n"+\ - " - Le sujet doit être immobile durant toutes la séance de prise de vue.\n"+\ - " - Les photos doivent être nettes : attention à la profondeur de champ.\n"+\ - " Les photos de personnes ou d'objet en mouvement sont déconseillées\n"+\ - " Les surfaces lisses ou réfléchissantes sont défavorables.\n"+\ - " - Si le sujet est central prendre une photo tous les 20°, soit 9 photos pour un 'demi-tour', 18 pour un tour complet.\n"+\ - " - Si le sujet est en 'ligne' le recouvrement entre photos doit être des 2/3 au minimum.\n"+\ - " - Tester la 'qualité' des photos au sein du chantier (voir les items du menu Outils).\n"+\ - " les photos ayant un mauvais score doivent être supprimées du chantier : elle peuvent faire échouer le traitement.\n"+\ - " - La présence des dimensions du capteur de l'appareil dans DIcoCamera.xml améliore le traitement.\n"+\ - " Cette présence est obligatoire si l'exif ne présente pas la focale équivalente 35mm.\n"+\ - " Pour ajouter la taille du capteur utiliser le menu 'Outils//metre à jour DicoCamera'.\n"+\ - "Précautions : \n" +\ - " Toutes les photos doivent être prises avec la même focale, ne pas utiliser la fonction autofocus.\n"+\ - " Eviter aussi la fonction 'anti tremblement' qui agit en modfiant la position du capteur.\n\n" +\ - "Options :\n"+\ - " - Tapioca : Si le sujet est central conserver les paramètres par défaut.\n" +\ - " - Tapioca : Si le sujet est en ligne choisir 'line' dans les options de Tapioca, \n" +\ - " puis delta = 1, si les photos se recouvrent au 2/3, \n" +\ - " ou delta = 2 voire +, si le recouvrement est plus important.\n\n" +\ - " - Tapas : Si l'appareil photo est un compact ou un smartphone choisir RadialBasic, \n" +\ - " Si l'appareil photo est un reflex haut de gamme choisir RadialExtended \n" +\ - " Si l'appareil photo est de moyenne gamme choisir RadialStd \n" +\ - " L'arrêt aprés Tapas est conseillé : la visualisation du nuage de points non densifié\n" +\ - " permet de définir un masque, 2D ou 3D, pour l'étape suivante.\n\n" +\ - " - Calibration : permet de définir un repère et une métrique(axe, plan et distance obligatoires).\n\n"+\ - " - Malt : pour le mode GeomImage indiquer une image maitresse, choisir la plus représentative du résultat souhaité.\n" +\ - " Seuls les points visibles sur cette image seront conservés dans le nuage de points.\n" +\ - " Sur cette image maitresse tracer le masque en 2 Dimensions délimitant la partie 'utile' de la photo.\n"+\ - " Le traitement avec masque sera accéléré et le résultat plus 'propre'.\n\n" +\ - " - C3DC : propose de définir un masque en 3D qui conservera tout le volume concerné.\n" +\ - " Alternative à Malt, le traitement est beaucoup plus rapide. Nécessite la dernière version de MicMac.\n\n"+\ - " - GPS : définir des points cotés et les placer sur 2 photos. La trace indique s'ils sont pris en compte\n"+\ + aide2 = _("Interface graphique pour lancer les modules de MICMAC : quelques conseils.") + "\n\n"+\ + _("Prises de vue :") + "\n"+\ + _(" - Le sujet doit être immobile durant toutes la séance de prise de vue.") + "\n"+\ + _(" - Le sujet doit être bien éclairé, la prise de vue en plein jour doit être recherchée.") + "\n"+\ + _(" - Les photos doivent être nettes, attention à la profondeur de champ :") + "\n"+\ + _(" utiliser la plus petite ouverture possible (nombre F le plus grand, par exemple 22).") + "\n"+\ + _(" - Les photos de personnes ou d'objet en mouvement sont déconseillées") + "\n"+\ + _(" - Les surfaces lisses ou réfléchissantes sont défavorables.") + "\n"+\ + _(" - Si le sujet est central prendre une photo tous les 20°, soit 9 photos pour un 'demi-tour', 18 pour un tour complet.") + "\n"+\ + _(" - Si le sujet est en 'ligne' le recouvrement entre photos doit être des 2/3.") + "\n"+\ + _(" - Tester la 'qualité' des photos au sein du chantier (voir les items du menu Outils).") + "\n"+\ + _(" les photos ayant un mauvais score (voir le menu Outils/Qualité des photos 'All') doivent être supprimées du chantier : ")+ "\n"+\ + _(" une seule mauvaise photo peut faire échouer le traitement.") + "\n"+\ + _(" - La présence des dimensions du capteur de l'appareil dans DIcoCamera.xml améliore le traitement.") + "\n"+\ + _(" Cette présence est obligatoire si l'exif ne présente pas la focale équivalente 35mm.") + "\n"+\ + _(" Pour ajouter la taille du capteur utiliser le menu 'Outils//mettre à jour DicoCamera'.") + "\n\n"+\ + _(" Précautions : ") + "\n"+\ + _(" Ne pas utiliser la fonction autofocus. Deux focales différentes maximum pour un même chantier.") + "\n"+\ + _(" Si il y a 2 focales différentes utiliser la calibration intrinsèque de Tapas.") + "\n"+\ + _(" Eviter aussi la fonction 'anti tremblement' qui agit en modfiant la position du capteur.") + "\n\n" +\ + _("Options :") + "\n"+\ + _(" - Tapioca : si le sujet est central conserver les paramètres par défaut.") + "\n" +\ + _(" L'échelle est la taille réduite de l'image (en pixels, ou -1 pour l'image entière) pour la recherche des points homologues.") + "\n" +\ + _(" Si le sujet est en ligne choisir 'line' dans les options de Tapioca, ") + "\n" +\ + _(" puis delta = 1, si les photos se recouvrent à moitiè, ") + "\n" +\ + _(" ou delta = 2 voire +, si le recouvrement est plus important.") + "\n\n" +\ + _(" L'option ALl recherche les points homologues sur toutes les paires de photos (ce qui peut faire beaucoup !)") + "\n" +\ + _(" L'option MulScale recherche les points homologues en 2 temps :") + "\n" +\ + _(" 1) sur toutes les paires avec une taille de photo réduite (typiquement 300)") + "\n" +\ + _(" 2) Seules les paires de photos ayant eu au moins 2 points homologues à cette échelle seront") + "\n" +\ + _(" retenues pour rechercher les points homologues à la seconde échelle. Gain de temps important possible.") + "\n" +\ + _(" - Tapas : si l'appareil photo est un compact ou un smartphone choisir RadialBasic, ") + "\n"+\ + _(" si l'appareil photo est un reflex haut de gamme choisir RadialExtended ") + "\n" +\ + _(" si l'appareil photo est de moyenne gamme choisir RadialStd") + "\n" +\ + _(" si les photos ont 2 focales alors choisir toutes celles qui ont la plus grande focale pour la calibration intrinsèque.") + "\n"+\ + _(" L'arrêt aprés Tapas est conseillé : la visualisation du nuage de points non densifié") + "\n" +\ + _(" permet de définir un masque, 2D ou 3D, pour l'étape suivante.") + "\n\n" +\ + _(" - Calibration : permet de définir un repère et une métrique (axe, plan et distance, tous obligatoires).") + "\n\n"+\ + _(" - Malt : pour le mode GeomImage indiquer une ou plusieurs images maîtresses.") + "\n" +\ + _(" Seuls les points visibles sur ces images seront conservés dans le nuage de points.") + "\n" +\ + _(" Sur ces images maîtresses tracer les masque délimitant la partie 'utile' de la photo.") + "\n"+\ + _(" Le résultat sera mis en couleur suivant les images maitresses.") + "\n"+\ + _(" (éviter trop de recouvrement entre les maîtresses !).") + "\n"+\ + _(" Le traitement avec masque sera accéléré et le résultat plus 'propre'.") + "\n\n" +\ + _(" - C3DC : propose de définir un masque en 3D qui conservera tout le volume concerné.") + "\n" +\ + _(" Alternative à Malt, le traitement est beaucoup plus rapide. Nécessite la dernière version de MicMac.") + "\n\n"+\ + _(" - GPS : définir au moins 3 points cotés et les placer sur 2 photos. La trace indique s'ils sont pris en compte") + "\n\n"+\ + _("Si MicMac ne trouve pas d'orientation ou pas de nuage de points :") + "\n\n"+\ + _(" - Examiner la qualité des photos (utiliser le menu outils/Qualité des photos): .") + "\n" +\ + _(" 1) Eliminer les photos ayant les plus mauvais scores") + "\n"+\ + _(" 2) si ce n'est pas suffisant ne garder que les meilleures photos (typiquement : moins de 10)") + "\n"+\ + _(" Penser que des photos floues ou avec un sujet brillant, lisse, mobile, transparent, vivant sont défavorables.")+ "\n"+\ + _(" 3) Augmenter l'échelle des photos pour tapioca, mettre -1 au lieu de la valeur par défaut.") + "\n"+\ + _(" 4) modifier le type d'appareil pour Tapas (radialstd ou radialbasic)") + "\n"+\ + _(" 5) vérifier la taille du capteur dans dicocamera, nécessaire si la focale equivalente 35 mm est absente de l'exif") + "\n"+\ + _(" 6) examiner la trace synthétique et la trace complète : MicMac donne quelques informations") + "\n"+\ + _(" 7) consulter le forum micmac (http://forum-micmac.forumprod.com)") + "\n"+\ + _(" 8) faites appel à l'assistance de l'interface (voir adresse dans l'a-propos)") + "\n\n"+\ "--------------------------------------------- "+self.titreFenetre+" ---------------------------------------------" - self.encadre (aide2,50,aligne='left',nouveauDepart='non') + self.cadreVide() + self.effaceBufferTrace() + self.ajoutLigne(aide2) + self.texte201.see("1.1") def commencer(self): - aide3= \ - " Pour commencer avec l'interface graphique MicMac :\n\n"+\ - " Tout d'abord : Installer MicMac.\n"+\ - " Puis : Installer Meshlab ou CloudCompare (pour afficher les nuages de points)\n\n"+\ - " Ensuite, dans cette interface graphique :\n\n"+\ - "1) Paramétrer l'interface : indiquer ou se trouvent le répertoire bin de MicMac et l'éxécutable Meshlab ou CloudCompare.\n"+\ - "2) Choisir quelques photos, pas plus de 5 pour commencer (menu MicMac).\n"+\ - "3) Lancer MicMac en laissant les paramètres par défaut (menu MicMac).\n"+\ - " Si tout va bien une vue en 3D non densifiée doit s'afficher, patience : cela peut être long.\n"+\ - "4) Si tout va bien alors modifier les paramétres pour la suite du traitement (Malt ou C3DC) (voir la doc).\n"+\ - " Puis re lancer MicMac pour obtenir une vue 3D densifiée.\n\n"+\ - "5) Si tout ne va pas bien re 'lancer MicMac' et annuler le traitement, puis :\n"\ - " Lire 'quelques conseils' (menu Aide).\n"+\ - " Tester la qualité des photos (menu Outils, aprés avoir paramètré exiftool).\n"+\ - " Examiner les traces (menu Edition),\n"+\ - " Consulter l'aide (menu Aide),\n"+\ - " Consulter le guide d'installation et de prise en main de l'interface.\n"+\ - " Consulter le forum MicMac sur le net, consulter la doc MicMac.\n"+\ - "6) Si une solution apparaît : modifier les options (menu MicMac).\n"+\ - " puis relancer le traitement.\n"+\ - "7) Si le problème persiste faire appel à l'assistance de l'interface (adresse mail dans l'A-propos)\n" + aide3 = \ + _(" Pour commencer avec l'interface graphique MicMac :") + "\n\n"+\ + _(" Tout d'abord : installer MicMac.") + "\n"+\ + _(" Puis : installer Meshlab ou CloudCompare (pour afficher les nuages de points)") + "\n\n"+\ + _(" Ensuite, dans cette interface graphique :") + "\n\n"+\ + _("1) Paramètrer l'interface : indiquer ou se trouvent le répertoire bin de MicMac et l'éxécutable Meshlab ou CloudCompare.") + "\n"+\ + _(" Indiquer éventuellement ou se trouvent exiftool et convert d'ImageMagick (en principe sous MicMac\\binaire-aux).") + "\n"+\ + _("2) Choisir quelques photos, par exemple du jeu d'essai gravillons, au moins 3 mais pas plus de 6 pour commencer (menu MicMac).") + "\n"+\ + _("3) Lancer MicMac en laissant les paramètres par défaut (menu MicMac).") + "\n"+\ + _(" Si tout va bien une vue en 3D non densifiée doit s'afficher, patience : cela peut être long.") + "\n"+\ + _("4) Si tout va bien alors modifier les options pour la suite du traitement (Malt ou C3DC) (voir la doc).") + "\n"+\ + _(" Puis re lancer MicMac pour obtenir une vue 3D densifiée.") + "\n\n"+\ + _("5) Si tout ne va pas bien re 'lancer MicMac' et annuler le traitement, puis :") + "\n"+\ + _(" Lire 'quelques conseils' (menu Aide).") + "\n"+\ + _(" Tester la qualité des photos (menu Outils).") + "\n"+\ + _(" Examiner les traces (menu Edition),") + "\n"+\ + _(" Consulter l'aide (menu Aide),") + "\n"+\ + _(" Consulter le guide d'installation et de prise en main de l'interface.") + "\n"+\ + _(" Consulter le forum MicMac sur le net, consulter la doc MicMac.") + "\n"+\ + _("6) Si une solution apparaît : modifier les options (menu MicMac).") + "\n"+\ + _(" puis relancer le traitement.") + "\n"+\ + _("7) Si le problème persiste faire appel à l'assistance de l'interface (adresse mail dans l'A-propos)") + "\n" self.encadre (aide3,50,aligne='left',nouveauDepart='non') + + def historiqueDesVersions(self): + aide4 = \ + _("Historique des versions diffusées sur le site de l'IGN") + "\n"+\ + "----------------------------------------------------------"+\ + "\n" + _("Version 1.5 : première version diffusée sur le site de l'IGN le 23/11/2015.") + "\n"+\ + "\n" + _("Version 1.55 : sous Windows le fichier paramètre est placé sous le répertoire APPDATA de l'utilisateur,") + "\n"+\ + chr(9)+chr(9)+_("ce qui règle les questions relatives aux droits d'accès en écriture. Mise en ligne le 04/12/2015.") + "\n"+\ + "\n" + _("Version 1.60 : ajout des fonctions :") + "\n"+\ + chr(9)+chr(9)+_("- Qualité des photos lors du dernier traitement") + "\n"+\ + chr(9)+chr(9)+_("- Exporter le chantier en cours") + "\n"+\ + chr(9)+chr(9)+_("- Importer un chantier (permet de recopier le chantier sur un autre répertoire, disque, ordinateur, système d'exploitation)") + "\n"+\ + chr(9)+chr(9)+_("- Les fichiers 'trace' sont enregistrés au format utf-8.") + "\n\n"+\ + _("Version 2.00 : ajout des fonctions :") + "\n"+\ + chr(9)+chr(9)+_("- Choix de photos pour la calibration intrinsèque par Tapas.") + "\n"+\ + chr(9)+chr(9)+_("- Possibilité de relancer Malt sans relancer Tapioca/Tapas tout en conservant les images 3D générées.") + "\n"+\ + chr(9)+chr(9)+_("- Conservation de plusieurs fichiers modele3D.ply après Malt pour un même chantier.") + "\n"+\ + chr(9)+chr(9)+_("- Choix du niveau de zoom d'arrêt de la procédure Malt : de 1 (par défaut) à 8.") + "\n"+\ + chr(9)+chr(9)+_("- Création de tous les fichiers .ply correspondants à tous les niveaux de zoom calculés.") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un item du menu édition listant et visualisant toutes les images 3D générées.") + "\n"+\ + chr(9)+chr(9)+_("- Choix du nombre de photos à retenir autour de l'image maître pour Malt.") + "\n"+\ + chr(9)+chr(9)+_("- Traitement des vidéos (par exemple GoPro) : décompactage, sélection, mise à jour de l'exif") + "\n"+\ + chr(9)+chr(9)+_("- Ajout de deux contrôles sur le lot des photos : mêmes dimensions, même focale.") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un item 'historique' dans le menu Aide.") + "\n"+\ + "\n" + _("Version 2.10")+chr(9)+_("- Ajout d'un item du menu édition fusionnant les images 3D.") + "\n"+\ + chr(9)+chr(9)+_("- Plusieurs images maîtresses, plusieurs masques.") + "\n"+\ + chr(9)+chr(9)+_("- Conversion automatique des fichiers PNG, BMP, GIF, TIF en JPG") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un item du menu Outils permettant de modifier les exifs. Diffusion restreinte à la DTer NC le 16/02/2016") + "\n"+\ + "\n" + _("Version 2.20 :")+chr(9)+_("- Maintien des options compatibles lors du choix de nouvelles photos. Février 2016") + "\n"+\ + "\n" + _("Version 2.30 : ")+\ + chr(9)+_("- Modification des options par défaut dans le menu outils.") + "\n"+\ + "\n" + _("Version 2.40 :")+chr(9)+_("- Choix de l'option (Statue ou QuickMac) pour C3DC. Avril 2016") + "\n"+\ + "\n" + _("Version 2.45 :")+chr(9)+_("- Référentiel GPS calculé après Tapas (et toujours avant Malt). La virgule est un séparateur décimal accepté.") + "\n"+\ + chr(9)+chr(9)+_("- Possiblité d'appliquer la calibration GPS sans relancer malt. Mai 2016") + "\n"+\ + "\n" + _("Version 2.50 :")+chr(9)+_("- Ajout de Tawny aprés Malt en mode Ortho, désactivation du message de lancement. Juin 2016") + "\n"+\ + "\n" + _("Version 3.00 :")+chr(9)+_("- Version bilingue Français/Anglais. Octobre 2016") + "\n"+\ + "\n" + _("Version 3.10 :")+chr(9)+_("- Choix des N meilleures photos pour un nouveau dossier. Novembre 2016") + "\n"+\ + "\n" + _("Version 3.20 :")+chr(9)+_("janvier 2017") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un choix pour Malt : AperoDeDenis, l'interface recherche pour vous les maîtresses et les photos correspondantes") + "\n"+\ + chr(9)+chr(9)+_("- Item de sélection des meilleures images pour créer un nouveau chantier. janvier 2017") + "\n"+\ + chr(9)+chr(9)+_("- Possibilité de saisir une unité avec la distance.") + "\n"+\ + chr(9)+chr(9)+_("- Lancement de Tapas accéléré : suppression du controle des photos") + "\n"+\ + chr(9)+chr(9)+_("- Les photos autour de la maîtresse pour Malt sont choisies parmi les meilleures en correspondances") + "\n"+\ + chr(9)+chr(9)+_("- Controle affiné des points GPS, message informatif détaillé") + "\n"+\ + chr(9)+chr(9)+_("- Possibilité de supprimer UN seul point GPS sur une photo") + "\n"+\ + "\n" + _("Version 3.30 :")+chr(9)+_("janvier 2017") + "\n"+\ + chr(9)+chr(9)+_("- Ajout de tarama : création d'une mosaïque aprés Tapas.") + "\n"+\ + chr(9)+chr(9)+_("- le mode Ortho de Malt utilise la mosaïque tarama, avec masque") + "\n"+\ + chr(9)+chr(9)+_("- drapage du nuage densifié par l'ortho mosaïque obtenue par Tawny") + "\n"+\ + chr(9)+chr(9)+_("- Possibilité d'inverser les masques 2D") + "\n"+\ + chr(9)+chr(9)+_("- Ouverture des mosaïques Tarama et Tawny par menu") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un menu 'expert' permettant de saisir une ligne de commande.") + "\n"+\ + "\n" + _("Version 3.31 :")+chr(9)+_("février 2017") + "\n"+\ + chr(9)+chr(9)+_("- Ajout d'un item du menu 'expert' : recopie les points GPS d'un chantier à un autre.") + "\n"+\ + "\n" + _("Version 3.34 :")+chr(9)+_("Janvier 2018") + "\n"+\ + chr(9)+chr(9)+_("- Du ménage! permet de conserver les résultats OU de supprimer tout le chantier.") + "\n"+\ + chr(9)+chr(9)+_("- Affichage de la taille du dossier.") + "\n"+\ + chr(9)+chr(9)+_("- Correction de régressions de la V 3.20.") + "\n"+\ + chr(9)+chr(9)+_("Remarque : la version 4.11 de décembre 2017 ajoute un item métier de calcul d'indice surfacique,") + "\n"+\ + "\n" + _("Version 5.0 :")+chr(9)+_("Janvier 2018") + "\n"+\ + chr(9)+chr(9)+_("la version suivante 5.0 supprime l'item 'indices surfaciques'.") + "\n"+\ + "----------------------------------------------------------" +# correction de : e remplacé par self.e dans MyDialog (fixe le problème du renommage des chantiers) +# ajout de self.pasDeFocales = False aprés la mise à jour des exifs. (fixe le problème du message erroné concerné les focales manquantes) +# modification de l'icone de la fenêtre = l'icone du cerema remplace le graindsel. +# possibilité de choisir le ménage : suppression totale ou conservation des résultats seuls +# Affichage du gain de place en MO aprés le ménage +# affichage de la taille du dossier en MO dans l'affichage de l'état du chantier +# test de la présence de sous répertoire dans afficheetat : +# si etatChantier>2 et pas de sous-répertoire alors etatChantier remis à 2 et +# message "chantier nettoyé" affiché + #self.encadre (aide4,50,aligne='left',nouveauDepart='non') + self.cadreVide() + self.effaceBufferTrace() + self.ajoutLigne(aide4) + self.texte201.see("1.1") def aPropos(self): - aide2=self.titreFenetre+("\n\nRéalisation Denis Jouin 2015\n\nLaboratoire Régional de Rouen\n\n"+ - "Direction Territoriale Normandie Centre\n\n CEREMA\n\ninterface-micmac@cerema.fr") + aide5=self.titreFenetre+("\n\n" + _("Réalisation Denis Jouin 2015-2016") + "\n\n" + _("Laboratoire Régional de Rouen") + "\n\n"+ + _("Direction Territoriale Normandie Centre") + "\n\n" + "CEREMA" + "\n\n" + "interface-micmac@cerema.fr") - self.encadre (aide2,aligne='center',nouveauDepart='non') + self.encadre (aide5,aligne='center',nouveauDepart='non') #ajout du logo du cerema si possible try: - self.logo = ttk.Frame(self.resul100) # cadre dans la fenetre ; affiche la photo sélectionnée - self.canvasLogo = tkinter.Canvas(self.logo,width = 225, height = 80) # Canvas pour revevoir l'image self.canvasLogo.pack(fill='both',expand = 1) self.logo.pack() self.imageLogo = Image.open(self.logoCerema) self.img = self.imageLogo.resize((225,80)) self.imgTk = ImageTk.PhotoImage(self.img) self.imgTk_id = self.canvasLogo.create_image(0,0,image = self.imgTk,anchor="nw") # affichage effectif de la photo dans canvasPhoto - ttk.Label(self.logo,text="MicMac est une réalisation de l'IGN").pack(pady=5) - except: - pass + if self.labelIgn.winfo_manager()!="pack": + self.labelIgn.pack(pady=5) + + except Exception as e: print(_("erreur canvas logo cerema : ")+str(e)) #ajout du logo IGN si possible if os.path.exists(self.logoIGN): - try: - self.logoIgn = ttk.Frame(self.resul100) # cadre dans la fenetre ; affiche la photo sélectionnée - self.canvasLogoIGN = tkinter.Canvas(self.logoIgn,width = 149, height = 162) # Canvas pour revevoir l'image + try: self.canvasLogoIGN.pack(fill='both',expand = 1) - self.logoIgn.pack(pady=5) - self.imageLogoIGN = Image.open(self.logoIGN) # self.logoIGN = nom du fichier png + self.logoIgn.pack(pady=5) + self.imageLogoIGN = Image.open(self.logoIGN) # self.logoIGN = nom du fichier png (ne pas confondre avec logoIgn en minuscule= frame) self.imgIGN = self.imageLogoIGN.resize((149,162)) self.imgTkIGN = ImageTk.PhotoImage(self.imgIGN) self.imgTk_idIGN = self.canvasLogoIGN.create_image(0,0,image = self.imgTkIGN,anchor="nw") # affichage effectif de la photo dans canvasPhoto @@ -4011,16 +7018,18 @@ def aPropos(self): ################################## Le menu FICHIER : nouveau, Ouverture, SAUVEGARDE ET RESTAURATION, PARAMETRES, outils divers ########################################################### - def sauveParam(self): # La sauvegarde ne concerne que 2 fichiers; fixes, sous le répertoire d'aperodedenis, - # pour les paramètres généraux : self.fichierParamMicmac - # pour le chantier en cours : self.fichierParamChantierEnCours + def sauveParam(self): # La sauvegarde ne concerne que 2 fichiers; fixes, sous le répertoire des paramètres, + # - pour les paramètres généraux : self.fichierParamMicmac + # - pour le chantier en cours : self.fichierParamChantierEnCours + # pour enregistrer le chantier en cours utiliser : + # - copierParamVersChantier() self.sauveParamMicMac() self.sauveParamChantier() def sauveParamChantier(self): - - try: - sauvegarde1=open(self.fichierParamChantierEnCours,mode='wb') + essai = (self.fichierParamChantierEnCours+"essai") # pour éviter d'écraser le fichier si le disque est plein + try: + sauvegarde1=open(essai,mode='wb') pickle.dump(( self.repertoireDesPhotos, self.photosAvecChemin, @@ -4038,55 +7047,92 @@ def sauveParamChantier(self): self.modeMalt.get(), self.fichierMasqueXML, self.repTravail, - self.photosPropresAvecChemin, + self.photosAvecChemin, # a supprimer (doublon avec r2) self.extensionChoisie, - self.nomMaitreSansExtension, + self.maitreSansExtension, self.etatDuChantier, self.dicoPointsGPSEnPlace, self.maitre, - self.masque, + self.mercurialMicMac, self.idPointGPS, self.dicoLigneHorizontale, self.dicoLigneVerticale, self.dicoCalibre, self.distance.get(), - self.monImage_MaitrePlan, # Nom de l'image maitresse du plan repere (sans extension) + self.monImage_MaitrePlan, # Nom de l'image maîtresse du plan repere (sans extension) self.monImage_PlanTif, # nom du masque correspondant self.etatSauvegarde, self.modeCheckedTapas.get(), - self.echelle4.get() + self.echelle4.get(), + self.photosPourCalibrationIntrinseque, + self.calibSeule.get(), + self.zoomF.get(), + self.photosUtilesAutourDuMaitre.get(), + self.modele3DEnCours, + self.typeDuChantier, + self.listeDesMaitresses, + self.listeDesMasques, + self.densification, + self.modeC3DC.get(), + self.tawny.get(), + self.tawnyParam.get(), + version, + self.exifsDesPhotos, + self.lancerTarama.get() ), sauvegarde1) sauvegarde1.close() + supprimeFichier(self.fichierParamChantierEnCours) + os.rename(essai,self.fichierParamChantierEnCours) except Exception as e: - print ('erreur sauveParamChantier : ',e) + print (_('erreur sauveParamChantier : '),str(e)) def sauveParamMicMac(self): - + essai = (self.fichierParamMicmac+"essai") # pour éviter d'écraser le fichier si le disque est plein try: - sauvegarde2=open(self.fichierParamMicmac,mode='wb') - pickle.dump((self.micMac, - self.meshlab, + sauvegarde2=open(essai,mode='wb') + repertoire = self.verifParamRep() + pickle.dump((repertoire[0], + repertoire[1], self.indiceTravail, self.tousLesChantiers, - self.exiftool, - self.mm3d + repertoire[2], + repertoire[3], + repertoire[4], + self.tacky, + version, + langue, + repertoire[5], + versionInternet, # dernière version lue sur Internet + # permet de repérer les nouvelles versions et de réactiver le message + self.messageVersion # bool : si vrai on prévient l'utilisateur qu'il y a une nouvelle version (si pas la même, sinon pas ), sauvegarde2) - sauvegarde2.close() + sauvegarde2.close() + supprimeFichier(self.fichierParamMicmac) + os.rename(essai,self.fichierParamMicmac) except Exception as e: # Controle que le programme a accès en écriture dans le répertoire d'installation - print ('erreur sauveParamMicMac : ',e) - texte = "L'interface doit être installée dans un répertoire ou vous avez les droits d'écriture.\n\n"+\ - "Installer l'interface AperoDeDenis à un emplacement ou vous avez ce droit.\n\n"+\ - "Répertoire actuel : "+self.repertoireScript+".\n\n"+\ - "Erreur rencontrée : "+str(e) - self.deuxBoutons(titre="Problème d'installation",question=texte,b1='OK',b2='') # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1 + print (_('erreur sauveParamMicMac : '),str(e)) + texte = _("L'interface doit être installée dans un répertoire ou vous avez les droits d'écriture.") + "\n\n"+\ + _("Installer l'interface AperoDeDenis à un emplacement ou vous avez ce droit.") + "\n\n"+\ + _("Répertoire actuel : ")+self.repertoireData+".\n\n"+\ + _("Erreur rencontrée : ")+str(e)+str(repertoire) + self.troisBoutons(titre=_("Problème d'installation"),question=texte,b1='OK',b2='') # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1 fin(1) - ###### Restauration paramètres : la restauration d'un chantier peut concerner un chantier archivé, dans ce cas on restaure un fichier dont le nom est passé en paramètre - + def verifParamRep(self): #Vérifie s'il existe un répertoire pour les outils de micmac et gère leur absence lors de la sauvegarde. + repertoire = [self.micMac, self.meshlab, self.exiftool, self.mm3d, self.convertMagick, self.ffmpeg] + cpt = 0 + while(cpt < 6): + if(repertoire[cpt] == self.noRep[cpt]): + repertoire[cpt] = "N\\A" ##Empêche de se retrouver avec une langue inconnue dans ses paramètres. + cpt +=1 + return repertoire + + ###### Restauration paramètres : + def restaureParamEnCours(self): try: @@ -4094,19 +7140,54 @@ def restaureParamEnCours(self): sauvegarde2 = open(self.fichierParamMicmac,mode='rb') r2=pickle.load(sauvegarde2) sauvegarde2.close() - self.micMac = r2[0] - self.meshlab = r2[1] + r3 = [] + r3 = self.verifNARep(r2) # sépare ce qui doit être traduit ou pas + self.micMac = r3[0] + self.meshlab = r3[1] self.indiceTravail = r2[2] self.tousLesChantiers = r2[3] - self.exiftool = r2[4] - self.mm3d = r2[5] # spécifique linux/windows - - self.CameraXML = os.path.join(os.path.dirname(self.micMac),self.dicoCameraGlobalRelatif) - - except Exception as e: print("Erreur restauration param généraux : ",e) - - self.mm3dOK = verifMm3d(self.mm3d) # Booléen indiquant si la version de MicMac permet la saisie de masque 3D - + self.exiftool = r3[2] + self.mm3d = r3[3] # spécifique linux/windows + self.convertMagick = r3[4] + self.tacky = r2[7] + #r2[8] est la version : inutile pour l'instant (v3.00) + #r2[9] est la langue + self.ffmpeg = r3[5] + self.versionInternetAncienne = r2[11] + self.messageVersion = r2[12] + except Exception as e: print(_("Erreur restauration param généraux : "),str(e)) + + threading.Thread(target=self.verifieVersion).start() + + # détermination du chemin pour dicocamera, de la version de mm3d, de la possibilité d'utiliser C3DC + + self.CameraXML = os.path.join(os.path.dirname(self.micMac),self.dicoCameraGlobalRelatif) + self.mercurialMicMac= mercurialMm3d(self.mm3d) # voir si cela va durer ! + self.mm3dOK = verifMm3d(self.mm3d) # Booléen indiquant si la version de MicMac permet la saisie de masque 3D + + # Aprés plantage durant Malt ou fusion des photos ou ply peuvent manquer : on tente une restauration + try: + [os.rename(os.path.splitext(e)[0],e) for e in self.photosAvecChemin if (os.path.exists(os.path.splitext(e)[0]) and not (os.path.exists(e)))] + [os.rename(e,os.path.splitext(e)[0]+".ply") for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".pyl"] # remise à l'état initial + except Exception as e: + print("erreur tentative restauration après plantage : ",str(e)) + # il reste le pb des photos déplacées pour la calibration + + def verifNARep(self, r2): + cpt = 0 + if r2.__len__()>10: repFfmpeg = r2[10] # pour assurer la compatibilité avec les anciennes versions ou self.ffmpeg n'était pas sauvé + else: repFfmpeg = self.ffmpeg + r3 = [r2[0], r2[1], r2[4], r2[5], r2[6], repFfmpeg] + while(cpt < 6): + if(r3[cpt] == "N\\A"): + r3[cpt] = self.noRep[cpt] + cpt +=1 + return r3 + + + ###### la restauration d'un chantier peut concerner un chantier archivé, + # dans ce cas on restaure un fichier dont le nom est passé en paramètre + def restaureParamChantier(self,fichier): # permet de restaurer les paramètres d'un chantier si besoin try: # s'il y a une sauvegarde alors on la restaure @@ -4119,192 +7200,447 @@ def restaureParamChantier(self,fichier): self.lesExtensions = r[3] self.maitreSansChemin = r[4] self.masqueSansChemin = r[5] - self.modeTapioca.set(r[6]) - self.echelle1.set(r[7]) - self.echelle2.set(r[8]) - self.delta.set(r[9]) - self.echelle3.set(r[10]) - self.arretApresTapas.set(r[11]) + self.modeTapioca.set (r[6]) + self.echelle1.set (r[7]) + self.echelle2.set (r[8]) + self.delta.set (r[9]) + self.echelle3.set (r[10]) + self.arretApresTapas.set (r[11]) self.listePointsGPS = r[12] - self.modeMalt.set(r[13]) + self.modeMalt.set (r[13]) self.fichierMasqueXML = r[14] self.repTravail = r[15] - self.definirFichiersTrace() self.chantier = os.path.basename(self.repTravail) - self.photosPropresAvecChemin = r[16] + photosAvecChemin = r[16] # a supprimer (doublon avec r2) self.extensionChoisie = r[17] - self.nomMaitreSansExtension = r[18] + self.maitreSansExtension = r[18] self.etatDuChantier = r[19] self.dicoPointsGPSEnPlace = r[20] - self.maitre = r[21] - self.masque = r[22] + self.maitre = r[21] # 22 disparu + self.mercurialMicMacChantier = r[22] self.idPointGPS = r[23] self.dicoLigneHorizontale = r[24] self.dicoLigneVerticale = r[25] self.dicoCalibre = r[26] - self.distance.set(r[27]) - self.monImage_MaitrePlan = r[28] # Nom de l'image maitresse du plan repere (sans extension) + self.distance.set (r[27]) + self.monImage_MaitrePlan = r[28] # Nom de l'image maîtresse du plan repere (sans extension) self.monImage_PlanTif = r[29] # nom du masque correspondant self.etatSauvegarde = r[30] - self.modeCheckedTapas.set(r[31]) - self.echelle4.set(r[32]) + self.modeCheckedTapas.set (r[31]) + self.echelle4.set (r[32]) + self.photosPourCalibrationIntrinseque = r[33] + self.calibSeule.set (r[34]) + self.zoomF.set (r[35]) + self.photosUtilesAutourDuMaitre.set(r[36]) + self.modele3DEnCours = r[37] + self.typeDuChantier = r[38] + self.listeDesMaitresses = r[39] + self.listeDesMasques = r[40] + self.densification = r[41] + self.modeC3DC.set (r[42]) + self.tawny.set (r[43]) + self.tawnyParam.set (r[44]) + # r[45] est la version : inutile pour l'instant (v2.61] + self.exifsDesPhotos = r[46] + self.lancerTarama.set (r[47]) + except Exception as e: print(_("Erreur restauration param chantier : "),str(e)) + + # pour assurer la compatibilité ascendante suite à l'ajout de l'incertitude dans la description des points GPS + # passage vers la version 2.60 de la liste des points GPS (un item de plus dans le tuple) + + if self.listePointsGPS.__len__()>0: + if self.listePointsGPS[0].__len__()==6: + self.listePointsGPS=[[a,nom,x,y,z,ident,"10 10 10"] for a,nom,x,y,z,ident in self.listePointsGPS] - self.item701.config(text="image maitresse = "+self.maitreSansChemin) - - except Exception as e: - pass + try: self.definirFichiersTrace() # attention : peut planter a juste titre si reptravail + except: print(_("erreur définir fichier trace, est normale lors d'une importation.")) + + # zoom OK, les valeurs 8,4,2,1 correspondent au nuage étape 5, 6, 7, 8 (la valeur 8 est initialisée par défaut + try: + if self.zoomF.get()=="8":self.etapeNuage = "5" + if self.zoomF.get()=="4":self.etapeNuage = "6" + if self.zoomF.get()=="2":self.etapeNuage = "7" + if self.zoomF.get()=="1":self.etapeNuage = "8" + except: pass + + # chemin constants pour la mosaique tarama + self.mosaiqueTaramaTIF = os.path.join(self.repTravail,"TA","TA_LeChantier.tif") + self.mosaiqueTaramaJPG = os.path.join(self.repTravail,"TA","TA_LeChantier.JPG") + self.masqueTarama = os.path.join(os.path.splitext(self.mosaiqueTaramaJPG)[0]+"_Masq.tif") + # Mise à jour des windgets pour les options de Malt (dépendent de la présence/absence de masques) + + self.miseAJourItem701_703() + self.photosCalibrationSansChemin = [os.path.basename(f) for f in self.photosPourCalibrationIntrinseque] + ########################### affiche les messages à l'écran : cadre, état, boites de dialogues standards, ménage def encadreEtTrace(self,texte,nbLignesmax=40,aligne='center'): self.ajoutLigne(texte) self.ecritureTraceMicMac() # on écrit la trace - self.encadre(texte,nbLignesmax,aligne) + self.encadre(texte,nbLignesmax,aligne,nouveauDepart='non') - def encadre(self,texte,nbLignesmax=38,aligne='center',nouveauDepart='oui'): + def encadre(self,texte,nbLignesmax=44,aligne='center',nouveauDepart='oui'): + if texte.__class__==tuple().__class__: texte=' '.join(texte) if texte.__class__==list().__class__: texte=' '.join(texte) + if texte.count('\n')>nbLignesmax: # limitation à nbLignesmax du nombre de lignes affichées texte='\n'.join(texte.splitlines()[0:nbLignesmax-5]) +'\n.......\n'+'\n'.join(texte.splitlines()[-3:]) self.menageEcran() - self.nbEncadre+=1 - if self.nbEncadre>6 and nouveauDepart=='oui' and self.systeme=='nt': + if nouveauDepart=='oui': + self.nbEncadre+=1 + if self.nbEncadre>=6 and nouveauDepart=='oui' and self.systeme=='nt': self.messageNouveauDepart = texte - self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peyt-être polluée par le traitement + self.nouveauDepart() # lance une fenêtre nouvelle sous windows (l'actuelle peut-être se polluer par certains traitements sous windows) return self.texte101.configure(text=texte,justify=aligne) - self.texte101Texte = texte # pour encadrePlus + self.texte101Texte = texte # pour encadrePlus self.resul100.pack() fenetre.title(self.etatSauvegarde+self.chantier+" - "+self.titreFenetre) - fenetre.focus_force() # force le focus (it is impolite !) + fenetre.focus_force() # force le focus (it is impolite !) fenetre.update() - def encadrePlus(self,plus): + def encadrePlus(self,plus,nbLignesmax=40): self.texte101Texte+=plus if len(self.texte101Texte.split("\n")[-1])>60: - self.texte101Texte+="\n" + self.texte101Texte+="\n" + if self.texte101Texte.count('\n')>nbLignesmax: # limitation à nbLignesmax du nombre de lignes affichées + self.texte101Texte='\n'.join(self.texte101Texte.splitlines()[0:nbLignesmax-5]) +'\n-------\n'+'\n'.join(self.texte101Texte.splitlines()[-3:]) self.texte101.configure(text=self.texte101Texte) fenetre.update() - time.sleep(0.01) + def menageEcran(self): # suppression écran (forget) de tous les FRAMES - self.listeFrames() - for a in self.l: - try: exec("self."+a+".pack_forget()") - except Exception as e : print("Erreur menage : ",e) - def listeFrames(self): # CREE LA LISTE DE TOUS LES FRAMES de la fenetre self - self.l=list() - for v,t in self.__dict__.items(): # un print (v,t) ici affiche l'identifiant arborescent des widgets (fenetre/frame/widget) - if t.__class__ in [ttk.Frame().__class__,ttk.Notebook().__class__]: - self.l.append(v) + # fermeture des écrans de saisie encore ouvert : + + self.fermerLaBoiteAOnglets() + self.fermerOptionsGoPro() + self.fermerModifExif() + + # fermeture des frames et notebook + + if self.item400.winfo_manager()=="pack": + self.item400.pack_forget() + if self.item450.winfo_manager()=="pack": + self.item450.pack_forget() + if self.item460.winfo_manager()=="pack": + self.item460.pack_forget() + if self.item470.winfo_manager()=="pack": + self.item470.pack_forget() + if self.item480.winfo_manager()=="pack": + self.item480.pack_forget() + + if self.item500.winfo_manager()=="pack": + self.item500.pack_forget() + if self.item510.winfo_manager()=="pack": + self.item510.pack_forget() + if self.item540.winfo_manager()=="pack": + self.item540.pack_forget() + if self.item520.winfo_manager()=="pack": + self.item520.pack_forget() + + if self.item700.winfo_manager()=="pack": + self.item700.pack_forget() + if self.item710.winfo_manager()=="pack": + self.item710.pack_forget() + if self.item720.winfo_manager()=="pack": + self.item720.pack_forget() + if self.item730.winfo_manager()=="pack": + self.item730.pack_forget() + + if self.item800.winfo_manager()=="pack": + self.item800.pack_forget() + + if self.item950.winfo_manager()=="pack": + self.item950.pack_forget() + if self.item960.winfo_manager()=="pack": + self.item960.pack_forget() + if self.item965.winfo_manager()=="pack": + self.item965.pack_forget() + if self.item970.winfo_manager()=="pack": + self.item970.pack_forget() + if self.item975.winfo_manager()=="pack": + self.item975.pack_forget() + if self.item980.winfo_manager()=="pack": + self.item980.pack_forget() + if self.item990.winfo_manager()=="pack": + self.item990.pack_forget() + + if self.item1000.winfo_manager()=="pack": + self.item1000.pack_forget() + if self.item2000.winfo_manager()=="pack": + self.item2000.pack_forget() + if self.item3000.winfo_manager()=="pack": + self.item3000.pack_forget() + if self.item7000.winfo_manager()=="pack": + self.item7000.pack_forget() + if self.item8000.winfo_manager()=="pack": + self.item8000.pack_forget() + if self.item9000.winfo_manager()=="pack": + self.item9000.pack_forget() + + if self.resul100.winfo_manager()=="pack": + self.resul100.pack_forget() + if self.resul200.winfo_manager()=="pack": + self.resul200.pack_forget() + if self.onglets.winfo_manager()=="pack": + self.onglets.pack_forget() + + if self.logo.winfo_manager()=="pack": + self.logo.pack_forget() + if self.logo1.winfo_manager()=="pack": + self.logo1.pack_forget() + if self.logoIgn.winfo_manager()=="pack": + self.logoIgn.pack_forget() + try: + if self.frame.winfo_manager()=="pack": + self.frame.pack_forget() + self.bulle.destroy() + except: pass + +## +## def listeFrames(self): # CREE LA LISTE DE TOUS LES FRAMES de la fenetre self +## self.l=list() +## for v,t in self.__dict__.items(): # un print (v,t) ici affiche l'identifiant arborescent des widgets (fenetre/frame/widget) +## if t.__class__ in [ttk.Frame().__class__,ttk.Notebook().__class__]: +## self.l.append(v) + + + def fermerLaBoiteAOnglets(self): # palliatif + # la boite à oglet n'est pas une fenêtre modale mais une frame.. + # on pallie à cela en proposant de la sauver ou pas lorsque l'on fait du ménage + # pour éviter de fermer brutalement + # la vraie solution serait de mettre la frame dans une fenêtre toplevel, modale, elle. + # le try récupére l'erreur si jamais l'interface n'existe plus. + try: + if self.fermetureOngletsEnCours == True: + return + if self.onglets.winfo_manager()=="": + return + self.fermetureOngletsEnCours = True + if self.troisBoutons(_("Fermer les options."),_("Enregistrer les options saisies ?"),b1=_("enregistrer"),b2=_("abandon"))==0: + self.finOptionsOK() + else: + self.finOptionsKO() + self.fermetureOngletsEnCours = False + except: pass + + def fermerOptionsGoPro(self): + if self.fermetureOptionsGoProEnCours == True: + return + if self.item2000.winfo_manager()=="": + return + self.fermetureOptionsGoProEnCours = True + if self.troisBoutons(_("Fermer les options vidéo."),_("Enregistrer les options vidéos saisies ?"),b1=_("enregistrer"),b2=_("abandon"))==0: + self.optionsGoProOK() + else: + self.optionsGoProKO() + self.fermetureOptionsGoProEnCours = False - ################################## 2 outils : envoi retour chariot et compte le nombre d'extensions différentes dans une lister de fichiers + def fermerModifExif(self): + if self.fermetureModifExif == True: + return + if self.item3000.winfo_manager()=="": + return + self.fermetureModifExif = True + if self.troisBoutons(_("Fermer la modification des exifs."),_("Enregistrer les valeurs saisies ?"),b1=_("enregistrer"),b2=_("abandon"))==0: + self.exifOK() + else: + self.exifKO() + self.fermetureModifExif = False - def envoiRetourChariot(self,dest): # dest étant le processus ouvert par popen - dest.communicate(input='t\n') +######################### recherche de la dernière version d'aperodedenis sur le net - def nombreDExtensionDifferentes(self,liste): - lesExtensions=set([os.path.splitext(x)[1].upper() for x in liste]) # on vérifie l'unicité de l'extension : - self.lesExtensions=list(lesExtensions) # liste pour être slicable - return len(self.lesExtensions) + def verifieVersion(self): # va lire la version dans le titre de la page GitHub, puis compare avec la version mémorisée. + # Affiche un message si besoin. + # lancé par un thread (pour éviter le retard éventuel de connexion à internet si pas de connexion + try: + sock = urllib.request.urlopen("https://github.com/micmacIGN/InterfaceCEREMA/tree/master/InterfaceCEREMA") + htmlLu = str(sock.read(30000)) + sock.close + moi = htmlLu.find("JOUIN") + titre = htmlLu.find("title=",moi) + debutTitre = titre+7 + finTitre = htmlLu.find('"',titre+9) + versionInternet = htmlLu[debutTitre:finTitre] + except Exception as e: + print(_("erreur connexion internet : "),str(e)) + return + + # Y-a-t-il une nouvelle version sur internet ? Si oui faut-il un message ? - #################################### Supprime (ou conserve) les répertoires de travail + if not versionInternet: return + if numeroVersion in versionInternet: + self.messageVersion = True # Version à jour; activation message pour le futur + elif (compteur==1 and + (self.versionInternetAncienne!=versionInternet # nouvelle version sur internet + and self.messageVersion) # version déjà vue mais acccord pour réaffichage + ): + self.avertirNouvelleVersion = True + + def avertissementNouvelleVersion(self): + if self.avertirNouvelleVersion: + retour = self.troisBoutons(titre=_("Nouvelle version de l'interface AperoDeDenis"), + question=_("Nouvelle version disponible sur Internet : ")+"\n"+ + versionInternet+"\n"+ + _("Téléchargement à l'adresse : ")+"\n\n"+ + "https://github.com/micmacIGN/InterfaceCEREMA/tree/master/InterfaceCEREMA", + b1=_("OK"), + b2=_("Accéder au site"), + b3=_("Ne plus me le rappeler")) + if retour == 2: + self.messageVersion = True + if retour == 1: + webbrowser.open("https://github.com/micmacIGN/InterfaceCEREMA/tree/master/InterfaceCEREMA") + self.messageVersion = True + if retour == 2: + self.messageVersion = False + self.avertirNouvelleVersion = False + + #################################### Supprime (ou conserve) les répertoires de travail def supprimeRepertoires(self): + self.menageEcran() + + # Y-a-t-il des chantiers ? if len(self.tousLesChantiers)==0: - texte='\nTous les répertoires de travail sont déjà supprimés.\n' - self.encadre(texte) - return + texte='\n' + _("Tous les chantiers sont déjà supprimés.") + "\n" + self.encadre(texte,nouveauDepart='non') + return + + # Oui il y a des chantiers ! + supprime = list() conserve = list() texte = str() attention = str() - self.tousLesChantiers.sort(key=os.path.basename) # tri suivant le nom du chantier + espaceGagne = int() + chantierEnCours = self.repTravail + self.choisirUnePhoto(self.tousLesChantiers, - titre='Chantiers à supprimer', + titre=_('Chantiers à nettoyer ou supprimer'), mode='extended', - message="Multiselection possible.", - boutonDeux="Annuler", - objets='repertoires') # renvoi : self.selectionPhotosAvecChemi + message=_("Multiselection possible."), + boutonDeux=_("Annuler"), + objets=_('repertoires')) # renvoi : self.selectionPhotosAvecChemin + # rien à faire + if len(self.selectionPhotosAvecChemin)==0: return - + + # Nettoyage effectif à faire + if len(self.selectionPhotosAvecChemin)==1: - self.deuxBoutons('Suppression des répertoires de travail superflus', - 'Le répertoire suivant va être supprimé, sans mise en corbeille : \n\n'+'\n'.join(self.selectionPhotosAvecChemin), - 'Confimez', - 'Annuler') + self.troisBoutons(_('Suppression ou nettoyage des répertoires de travail superflus'), + _('Le chantier suivant va être supprimé ou nettoyé :') + '\n\n'+'\n'.join(self.selectionPhotosAvecChemin), + _('Supprimer totalement le chantier'), + _('Nettoyer le chantier, conserver les résultats'), + _('Annuler')) if len(self.selectionPhotosAvecChemin)>1: if self.repTravail in self.selectionPhotosAvecChemin: - attention="ATTENTION : le chantier en cours va être supprimé.\n\n" - self.deuxBoutons('Suppression des répertoires de travail superflus', - attention+'Vont être supprimés les répertoires suivants, sans mise en corbeille : \n\n'+'\n'.join(self.selectionPhotosAvecChemin), - 'Confimez','Annuler') - if self.bouton==1 or self.bouton==-1: #abandon par annulation (1) ou par fermeture de la fenêtre (-1) + attention=_("ATTENTION : le chantier en cours va être nettoyéé.") + "\n\n" + + self.troisBoutons(_('Suppression ou nettoyage des répertoires de travail superflus'), + _('Les chantiers suivant vont être supprimés ou nettoyés :') + '\n\n'+'\n'.join(self.selectionPhotosAvecChemin), + _('Supprimer totalement les chantiers'), + _('Nettoyer les chantier, conserver les résultats'), + _('Annuler')) + + if self.bouton==2 or self.bouton==-1: # abandon par annulation (1) ou par fermeture de la fenêtre (-1) return - for e in self.selectionPhotosAvecChemin: - if os.path.exists(e): - if self.repTravail == e: - self.etatDuChantier = -1 - texte="Le précédent chantier "" "+self.chantier+" "" est en cours de suppression.\n" - self.nouveauChantier() - time.sleep(0.1) - try: shutil.rmtree(e,False,self.echecSuppression(e)) # il semble que la racine reste présente il faut ensuite la supprimer - except: pass - try: os.rmdir(e) - except: pass - if os.path.exists(e): - ajout(conserve,e) + if self.bouton==0: # suppression totale des répertoires + self.encadre(_("Suppression en cours...."),nouveauDepart="non") + for e in self.selectionPhotosAvecChemin: + if os.path.exists(e): + espaceGagne+=sizeDirectoryMO(e) + if self.repTravail==e: + self.etatDuChantier = -1 + texte=_("Le chantier en cours %s est supprimé.") % (self.chantier)+ "\n" + self.nouveauChantier() + time.sleep(0.1) + try: shutil.rmtree(e) # il semble que la racine reste présente il faut ensuite la supprimer + except: pass + try: os.rmdir(e) + except: pass + if os.path.exists(e): + ajout(conserve,e) + else: + try: + ajout(supprime,e) + self.tousLesChantiers.remove(e) + except: pass + self.encadrePlus("...") + if len(supprime)>=1: + texte = texte+_("Compte rendu de la suppression :") + "\n\n" + _("Repertoires supprimés :") + "\n\n" + "\n".join(supprime)+"\n" else: - try: - ajout(supprime,e) - self.tousLesChantiers.remove(e) - except: pass - if len(supprime)>=1: - texte = texte+"Compte rendu de la suppression : \n\nRepertoires supprimés : \n\n"+'\n'.join(supprime)+"\n" - else: - texte = texte+"Compte rendu de la suppression : \n\nAucun répertoire supprimé.\n\n"+'\n'.join(supprime)+"\n" - - if len(conserve)==0: - texte = texte+'\n\nTous les chantiers demandés sont supprimés.' - elif len(conserve)==1: - texte = texte+'\n\nIl reste un chantier impossible à supprimer maintenant : \n\n'+'\n'.join(conserve) - else: - texte = texte+'\n\nIl reste des chantiers impossibles à supprimer maintenant : \n\n'+'\n'.join(conserve) - self.sauveParam() # mémorisation de la suppression - self.encadre(texte) + texte = texte+_("Compte rendu de la suppression :") + "\n\n" + _("Aucun répertoire supprimé.") + "\n\n"+'\n'.join(supprime)+"\n" + + if len(conserve)==0: + texte = texte+'\n\n' + _('Tous les chantiers demandés sont supprimés.') + elif len(conserve)==1: + texte = texte+'\n\n' + _('Il reste un chantier impossible à supprimer maintenant : ') + '\n\n'+'\n'.join(conserve) + else: + texte = texte+'\n\n' + _('Il reste des chantiers impossibles à supprimer maintenant : ') + '\n\n'+'\n'.join(conserve) + texte+="\n\n"+_("Espace disque récupéré : ")+str(espaceGagne)+" MO" + self.sauveParam() # mémorisation de la suppression + self.encadre(texte,nouveauDepart='non') + return + + # Nettoyage chantiers + + if self.bouton==1: # suppression des sous répertoires, conserve les résultats + self.encadre(_("Suppression des sous-répertoires en cours...."),nouveauDepart="non") + for e in self.selectionPhotosAvecChemin: + if os.path.exists(e): + rep = [f for f in os.listdir(e) if os.path.isdir(os.path.join(e, f))] + for r in rep: + espaceGagne+=sizeDirectoryMO(r) + try: + shutil.rmtree(r) + except: + espaceGagne-=sizeDirectoryMO(r) + texte = "Ménage effectué" + texte += "\n\n"+_("Espace disque récupéré : ")+str(espaceGagne)+" MO" + + self.encadre(texte,nouveauDepart='non') + return - def echecSuppression(self,e): - try: - time.sleep(0.05) - os.rmdir(e) - except: - pass + ############################### Message proposant une question et deux, trois ou 4 Boutons + # si b2="" alors pas de second bouton retour : 0, 1, 2, 3 : numéro du bouton + def troisBoutons(self,titre=_('Choisir'),question=_("Choisir : "),b1='OK',b2='KO',b3=None,b4=None): - ############################### Message proposant une question et deux Boutons OK, Annuler - # si b2="" alors pas de second bouton - def deuxBoutons(self,titre='Choisir',question="Choisir : ",b1='OK',b2='KO'): # b1 rennvoie 0, b2 renvoie 1 ; fermer fenetre = -1, + # positionne self.bouton et le renvoie : b1 = 0, b2 = 1 b3 = 2 b4 = 3; fermer fenetre = -1, try: self.bouton = -1 self.resul300 = tkinter.Toplevel(height=50,relief='sunken') fenetreIcone(self.resul300) self.resul300.title(titre) + if question.count('\n')>15: # limitation à nbLignesmax du nombre de lignes affichées + question='\n'.join(question.splitlines()[0:10]) +'\n.......\n'+'\n'.join(question.splitlines()[-3:]) self.texte301=ttk.Label(self.resul300, text=question) self.texte301.pack(pady=10,padx=10) self.texte302=ttk.Button(self.resul300, text=b1,command=self.bouton1) self.texte302.pack(pady=5) - if b2!="": # autorise un seul bouton + if b2!="": # autorise un seul bouton self.texte303=ttk.Button(self.resul300, text=b2,command=self.bouton2) self.texte303.pack(pady=5) + if b3!=None: # autorise un seul bouton + self.texte304=ttk.Button(self.resul300, text=b3,command=self.bouton3) + self.texte304.pack(pady=5) + if b4!=None: # autorise un seul bouton + self.texte305=ttk.Button(self.resul300, text=b4,command=self.bouton4) + self.texte305.pack(pady=5) self.resul300.transient(fenetre) # 3 commandes pour définir la fenêtre comme modale pour l'application self.resul300.grab_set() + self.resul300.focus_force() fenetre.wait_window(self.resul300) self.resul300.destroy() return self.bouton @@ -4320,20 +7656,23 @@ def bouton2(self): self.bouton = 1 self.resul300.destroy() + def bouton3(self): + self.bouton = 2 + self.resul300.destroy() + + def bouton4(self): + self.bouton = 3 + self.resul300.destroy() + ############################### Prépare un cadre pour Afficher une trace dans la fenêtre def cadreVide(self): self.menageEcran() - fenetre.update() # rafraichissement avant agrandissement - self.resul200 = ttk.Frame(fenetre,height=100,relief='sunken') # fenêtre texte pour afficher le bilan - self.scrollbar = ttk.Scrollbar(self.resul200) - self.scrollbar.pack(side='right',fill='y',expand=1) - self.texte201 = tkinter.Text(self.resul200,width=200,height=100,yscrollcommand = self.scrollbar.set,wrap='word') - self.texte201.pack() - self.resul200.pack() - self.scrollbar.config(command=self.yviewTexte) - + fenetre.update() # rafraichissement avant agrandissement + self.texte201.delete("0.0","end") + self.resul200.pack() + def yviewTexte(self, *args): if args[0] == 'scroll': self.texte201.yview_scroll(args[1],args[2]) @@ -4342,20 +7681,31 @@ def yviewTexte(self, *args): ################################## lance une procédure et éxécute une commande sur chaque ligne de l'output ################################################ - def lanceCommande(self,commande,filtre=lambda e: e,info="",attendre=True): + def lanceCommande(self,commande,filtre=lambda e: e,info="",attendre=True): + commande = [e for e in commande if e.__len__()>0] # suppression des arguments "vides" commandeTexte=" ".join(commande) # Format concaténé des arguments - self.ajoutLigne("\n\n"+heure()+" : Lancement de "+commandeTexte+"\n\n"+info+"\n") - exe = subprocess.Popen(commande, - shell=self.shell, - stdout=subprocess.PIPE, # ne pas définir stdin car sinon il faut le satisfaire - #stdin=subprocess.PIPE, # en fait il faut sans doute.... doute... - stderr=subprocess.STDOUT, - universal_newlines=True) + self.ajoutLigne("\n\n"+heure()+_(" : lancement de ")+commandeTexte+"\n\n"+info+"\n") + + try: + exe = subprocess.Popen(commande, + shell=self.shell, + stdout=subprocess.PIPE, # ne pas définir stdin car sinon il faut le satisfaire + stderr=subprocess.STDOUT, + universal_newlines=True) + except Exception as e: + self.ajoutLigne("\n"+_("erreur lors de l'éxécution de la commande :") + "\n"+str(e)+"\n") + self.ajoutLigne("\n"+heure()+_(" : fin de ")+commandeTexte+"\n") + return if not attendre: # par exemple pour lancer meshlab on n'attend pas la fin return + if "exe" not in locals(): + self.ajoutLigne("\n"+_("erreur lors de l'éxécution de la commande.") + "\n") + self.ajoutLigne("\n"+heure()+_(" : fin de ")+commandeTexte+"\n") + return + ligne=exe.stdout.readline() while ligne: @@ -4368,22 +7718,37 @@ def lanceCommande(self,commande,filtre=lambda e: e,info="",attendre=True): try: ligne=exe.stdout.readline() # ligne suivante, jusqu'à la fin du fichier, sauf décès (anormal) du processus père except: - print("erreur lecture output : ",commandeTexte) + print(_("erreur lecture output : "),commandeTexte) break # si la lecture ne se fait pas c'est que le processus est "mort", on arrête while exe.poll()==None: # on attend la fin du process, si pas fini (en principe : fini) time.sleep(0.1) pass - self.ajoutLigne("\n"+heure()+" : Fin de "+commandeTexte+"\n") + self.ajoutLigne("\n"+heure()+_(" : fin de ")+commandeTexte+"\n") - # Fichiers TRACE + ########################## Opérations sur les Fichiers TRACE - def definirFichiersTrace(self): # crée les fichiers à vide + def definirFichiersTrace(self): # affectation des noms des fichiers trace. pas de création : en effet le plus souvent ils existent déjà, il faut seulement les retrouver if self.repTravail != "": - self.TraceMicMacSynthese = self.repTravail+os.path.sep+'Trace_MicMac_Synthese.txt' - self.TraceMicMacComplete = self.repTravail+os.path.sep+'Trace_MicMac_Complete.txt' + self.TraceMicMacSynthese = os.path.join(self.repTravail,'Trace_MicMac_Synthese.txt') + self.TraceMicMacComplete = os.path.join(self.repTravail,'Trace_MicMac_Complete.txt') os.chdir(self.repTravail) # on se met dans le répertoire de travail, indispensable + + def initialisationFichiersTrace(self): # vide les fichiers et ecrit une nouvelle entête avec le nom des photos + open(self.TraceMicMacSynthese,'w').close() # création d'un fichier de trace, vide + open(self.TraceMicMacComplete,'w').close() # création d'un fichier de trace, vide + self.effaceBufferTrace() # RAZ d'un ahjoutLigne éventuel (notamment par affichage de la trace ) + self.ajoutLigne(heure()+" : "+self.titreFenetre+"\n-----------------------\n") + self.ajoutTraceComplete(_("Trace complète")) + self.ajoutTraceSynthese(_("Trace synthétique")) + self.ajoutLigne("\n-----------------------\n\n") + if len(self.photosAvecChemin)>0: + self.ajoutLigne(heure()+ "\n\n" + _("Choix des photos :") + "\n"+"\n".join(self.photosAvecChemin)) + self.ajoutLigne("\n\n" + _("répertoire du chantier :") + "\n"+self.repTravail+"\n\n") + self.ajoutLigne(_("Version MicMac : ")+self.mercurialMicMac+"\n") + self.ecritureTraceMicMac() + # ajout de lignes dans les traces @@ -4400,9 +7765,8 @@ def ajoutTraceComplete(self,lue=''): if lue==None: return self.lignePourTrace = self.lignePourTrace+str(lue) # la trace détaillée en fin de MicMac, dans le répertoire de travail, sous le nom traceTotale - print(lue) - except Exception as e: - print("Erreur ajout trace complète : ",str(lue)," erreur=",e) + except Exception as e: print(e) + def ajoutTraceSynthese(self,filtree=''): try: @@ -4410,35 +7774,41 @@ def ajoutTraceSynthese(self,filtree=''): return if filtree==None: return + # suppression des lignes comportant 2 * en début : info IGN répétitive + if filtree[0:2]=="**": + return + self.ligneFiltre = self.ligneFiltre+str(filtree) # la trace synthétique self.texte201.insert('end',str(filtree)) self.texte201.update() self.texte201.see('end') - except Exception as e: pass + except Exception as e: print(e) + def effaceBufferTrace(self): - + try: + self.texte201.delete("0.0",'end') + except: pass self.lignePourTrace = str() self.ligneFiltre = str() # écrire dans les traces def ecritureTraceMicMac(self): # écriture en Ajout des fichiers trace + self.definirFichiersTrace() try: - with open(self.TraceMicMacSynthese,'a') as infile: + with open(self.TraceMicMacSynthese,'a', encoding='utf-8') as infile: infile.write(self.ligneFiltre) - with open(self.TraceMicMacComplete,'a') as infile: + with open(self.TraceMicMacComplete,'a', encoding='utf-8') as infile: infile.write(self.lignePourTrace) - self.effaceBufferTrace() - except Exception as e: - print ('erreur ecritureTraceMicMac : ',e,"\ntraces : ",self.TraceMicMacSynthese," et ",self.TraceMicMacComplete) + print (_('erreur ecritureTraceMicMac : '),str(e),"\ntraces : ",self.TraceMicMacSynthese," et ",self.TraceMicMacComplete) - + self.effaceBufferTrace() - ############################### Choix d'une image dans la liste des images retenues avec scrollbar : charge self.selectionPhotosAvecChemin + ############################### Choix d'une image dans la liste des images retenues avec scrollbar : charge self.selectionPhotosAvecChemin, gadgets """ les deux autres présentations sous forme de dialogue : @@ -4449,39 +7819,43 @@ def ecritureTraceMicMac(self): # écrit # en retour : self.selectionPhotosAvecChemin def choisirUnePhoto(self, # en retour liste : self.selectionPhotosAvecChemin - listeAvecChemin, - titre='Choisir une photo', - message="Cliquer pour choisir une ou plusieurs photos : ", - mode='extended', # autre mode = "single" - messageBouton="OK", + listeAvecChemin, # liste des noms de fichiers ou répertoires à afficher pour le choix + titre=_('Choisir une photo'), # titre de la fenêtre + message=_("Cliquer pour choisir une ou plusieurs photos : "), # entête de la liste + mode='extended', # par défaut sélection multiple, autre mode = "single" + messageBouton=_("OK"), # message sur le premier bouton boutonDeux=None, # texte d'un second bouton : fermeture, renvoyant une liste vide - dicoPoints=None, - objets='photos'): # défaut : pas de dictionnaire de points à afficher - self.selectionPhotosAvecChemin = list() # sélection : vide pour l'instant ! - self.cherche = str() # recherche - self.fermerVisu = False # permet d'identifier la sortie par le second bouton si = True (!= sortie par fermeture fenêtre) + dicoPoints=None, # dictionnaire de points à afficher : key = (nom point, photo, identifiant), value = (x,y) + objets='photos', # par défaut la liste est une liste de fichiers, alternative : répertoires, ply + bulles=dict()): # dictionnaires d'info bulle : key = photo, value = infobulle if len(listeAvecChemin)==0: # pas de photos : on sort - self.encadre("Pas de photos pour cette demande.", + self.encadre(_("Pas de photos pour cette demande."), nouveauDepart="non") - return - l = [ e for e in listeAvecChemin if not os.path.exists(e)] #si des photos manquent : abandon ! - if len(l)>0 and objets=='photos': - texte="Les photos suivantes sont absentes du disque :"+"\n".join(l)+"\nDossier corrompu. Traitement interrompu." - self.encadre(texte,nouveauDepart="non") - return - self.dicoPointsAAfficher = dicoPoints # pour passer l'info à retailleEtAffiche + return + self.selectionPhotosAvecChemin = list() # sélection : vide pour l'instant ! + self.cherche = str() # recherche + self.fermerVisu = False # permet d'identifier la sortie par le second bouton si = True (!= sortie par fermeture fenêtre) + + l = [ e for e in listeAvecChemin if not (os.path.exists(e))] # BIS : si des photos ou répertoires manquent encore : abandon ! + if len(l)>0 and objets in ('photos','ply'): + # les fichiers absents peuvent être des fichiers "pour calibration" : ils doivent alors être retirés de la liste + noCalib = [f for f in l if os.path.basename(f) not in [os.path.basename(g) for g in self.photosPourCalibrationIntrinseque]] + if len(noCalib)>0: + texte=_("Les fichiers suivants sont absents du disque :") + "\n\n".join(l)+"\n" + _("Dossier corrompu. Traitement interrompu.") + self.encadre(texte,nouveauDepart="non") + return + # restriction de la liste aux fichiers non calibrant : + listeAvecChemin = [ h for h in listeAvecChemin if os.path.basename(h) not in [os.path.basename(i) for i in self.photosPourCalibrationIntrinseque]] + self.dicoPointsAAfficher = dicoPoints # pour passer l'info à afficherTousLesPointsDuDico + self.dicoInfoBullesAAfficher = bulles # pour passer l'info à afficherLesInfosBullesDuDico self.fermerVisuPhoto() # pour éviter les fenêtres multiples self.listeChoisir = list(set(listeAvecChemin)) # liste de choix par copie de la liste ou du tuple paramètre, sans doublons - self.listeChoisir.sort() #tri alpha + self.listeChoisir.sort(key=os.path.basename) # tri alpha listeSansChemin = [os.path.basename(e) for e in self.listeChoisir] self.topVisuPhoto = tkinter.Toplevel(fenetre,relief='sunken') # fenêtre principale de choix de la photo (maitre, ou autre) self.topVisuPhoto.title(titre) - self.topVisuPhoto.geometry("400x400+100+200") + self.topVisuPhoto.geometry("400x450+200+300") fenetreIcone(self.topVisuPhoto) - """textvariable : associe le texte du label à une variable de type StringVar. Si la variable change - de valeur, le texte change. Voir chapitre tk01 §7. Attention à l'utilisation des - StringVar : il faut créer la variable, l'affecter par la méthode set(), la consulter - par la méthode get().""" self.invitePhotoMessageInitial = message self.invitePhotoMessage = tkinter.StringVar() self.invitePhotoMessage.set(self.invitePhotoMessageInitial) @@ -4489,28 +7863,34 @@ def choisirUnePhoto(self, # en ret self.invitePhoto.pack(padx=5,pady=5,ipadx=5,ipady=5) frameSelect = ttk.Frame(self.topVisuPhoto) # cadre dans la fenêtre: pour afficher la boite à liste - scrollbar = ttk.Scrollbar(frameSelect, orient='vertical') #barre de défilement + scrollbar = ttk.Scrollbar(frameSelect, orient='vertical') # barre de défilement - self.selectionPhotos = tkinter.Listbox(frameSelect,selectmode=mode,yscrollcommand=scrollbar.set) + self.selectionPhotos = tkinter.Listbox(frameSelect, + selectmode=mode, + yscrollcommand=scrollbar.set, + width=min(250,(5+max(len (r) for r in listeSansChemin)))) self.selectionPhotos.select_set(1) self.selectionPhotos.bind("", self.upDown) self.selectionPhotos.bind("", self.upDown) self.selectionPhotos.bind("", self.upDown) self.selectionPhotos.bind("", self.upDown) - self.selectionPhotos.bind("", self.lettre) + self.selectionPhotos.bind("", self.lettre) self.selectionPhotos.pack(side='left', fill='both', expand=1) self.selectionPhotos.focus_set() - + scrollbar.config(command=self.yview) scrollbar.pack(side='right', fill='y') for i in listeSansChemin: # remplissage de la liste - self.selectionPhotos.insert('end',i) + self.selectionPhotos.insert('end',i) + l=[os.path.basename(e) for e in list(self.dicoInfoBullesAAfficher.keys())] + if i in l: + self.selectionPhotos.itemconfig("end",bg='yellow') frameSelect.pack() # fin de la boite à liste self.b1 = ttk.Button(self.topVisuPhoto,text=messageBouton,command=self.validPhoto) # le premier bouton (fermer ou OK if boutonDeux!=None: - c = ttk.Button(self.topVisuPhoto,text=boutonDeux,command=self.cloreVisuPhoto) #le second bouon si demandé + c = ttk.Button(self.topVisuPhoto,text=boutonDeux,command=self.cloreVisuPhoto) # le second bouon si demandé self.b1.pack(pady=5) c.pack(pady=5) else: @@ -4520,11 +7900,22 @@ def choisirUnePhoto(self, # en ret self.canvasPhoto = tkinter.Canvas(foto,width = 200, height = 200) # Canvas pour revevoir l'image self.canvasPhoto.pack(fill='both',expand = 1) foto.pack() + if bulles==dict(): + self.selectionPhotos.select_set(0) # si pas de dictionnaire sélection de la première photos (sinon colorisation &éventuelle de la première photo) + else: + self.retailleEtAffichePhoto(self.listeChoisir[0]) # pour afficher la première photo, même s'il n'y a pas de sélection + self.current = self.selectionPhotos.curselection() # sélection courante + self.list_has_changed(self.current) # la sélection est définie : on réagit + + ########################################################## + # poll : lance retaille et affiche la photo (retailleEtAffichePhoto), qui lance afficherTousLesPointsDuDico et afficherLesInfosBullesDuDico + # affiche les points du dictionnaire et une info bulle indiquant le nombre de points + # affiche les infos bulles de 'bulles' + # réagit aux changements de sélection par l'utilisateur - self.selectionPhotos.select_set(0) # sélection de la première photos - self.current = None # pas de photo choisie par l'utilisateur - self.poll() # lance la boucle infinie d'attente + self.poll() # essentiel : lance la boucle infinie d'attente + ########################################################## self.topVisuPhoto.protocol("WM_DELETE_WINDOW", self.fermerVisuPhoto) # Fonction a éxécuter lors de la sortie du programme self.topVisuPhoto.transient(fenetre) # 3 commandes pour définir la fenêtre comme modale pour l'application self.topVisuPhoto.grab_set() @@ -4532,6 +7923,271 @@ def choisirUnePhoto(self, # en ret try : self.bulle.destroy() except: pass +########################################## Traitement des données GoPro ############################################## + + + # saisie des options de la GoPro + + def optionsGoPro(self): + self.sauveOptionsGoPro() # en cas d'annulation par l'utilisateur + self.menageEcran() + self.item2000.pack() + + + return + + # Aprés saisie des options de la GoPro : + + def optionsGoProOK(self): + self.item2000.pack_forget() # fermer l'item (pour évitr la question par menageEcran) + self.encadre(_("Options GoPro modifiées"),nouveauDepart='non') + + def optionsGoProKO(self): # l'utilisateur abandonne les modifs + + self.goProMaker.set(self.goProMakerSave) + self.goProFocale35.set(self.goProFocale35Save) + self.goProFocale.set(self.goProFocaleSave) + self.goProNomCamera.set(self.goProNomCameraSave) + self.goProNbParSec.set(self.goProNbParSecSave) # taux de conservation des photos pour DIV + self.goProEchelle.set(self.goProEchelleSave) # pour tapioca + self.goProDelta.set(self.goProDeltaSave) + self.item2000.pack_forget() # fermer l'item (pour évitr la question par menageEcran) + self.encadre(_("Abandon : options GoPro inchangées."),nouveauDepart='non') + + def sauveOptionsGoPro(self): # l'utilisateur valide les modifs + + self.goProMakerSave = self.goProMaker.get() + self.goProFocale35Save = self.goProFocale35.get() + self.goProFocaleSave = self.goProFocale.get() + self.goProNomCameraSave = self.goProNomCamera.get() + self.goProNbParSecSave = self.goProNbParSec.get() # taux de conservation des photos pour DIV + self.goProEchelleSave = self.goProEchelle.get() # pour tapioca + self.goProDeltaSave = self.goProDelta.get() + + # Choix d'une vidéo et extraction des photos : + + def laVideo(self): # choix de la video + + self.fermerVisuPhoto() # s'il y a une visualisation en cours des photos ou du masque on la ferme + if verifierSiExecutable(self.ffmpeg)==False: + self.encadre(_("L'outil ffmpeg n'est pas installé sur votre ordinateur. Traitement des vidéo GoPro impossible."),nouveauDepart='non') + return + + repIni = "" # répertoire initial de la boite de dialogue + if os.path.isdir(self.repertoireDesPhotos): + repIni = self.repertoireDesPhotos + + video = tkinter.filedialog.askopenfilename(title=_("Choisir la video issue d'un appareil %(GoProMaker)s %(GoProName)s (sinon modifier les options)") % {"GoProMaker" : self.goProMaker.get(), "GoProName" : self.goProNomCamera.get()}, + initialdir=repIni, + filetypes=[(_("Video"),("*.mp4","*.MP4","*.MOV","*.mov")),(_("Tous"),"*")], + multiple=False) + + if len(video)==0: + self.encadre(_("Abandon, aucune sélection,\n le chantier reste inchangé.") + "\n",nouveauDepart='non') + return + + if os.path.splitext(video)[1].upper() not in ".MP4": + self.encadre(_("La version actuelle ne traite que les videos au format MP4, or le format des photos est %s. Désolé.") % (os.path.splitext(video)[1]) ,nouveauDepart='non' ) + #return + + # Quel répertoire pour le chantier ? + + self.nouveauChantier() # Enregistre le chantier précédent, réinitialise les valeurs par défaut prépare un chantier vide avec le répertoire de travail par défaut + retour = self.quelChantier(video) # positionne un nouveau self.repTravail en fonction du répertoire de la video, donne un nom au chantier + if retour!=None: + self.encadre(retour,nouveauDepart="non") + return # y a un pb + os.chdir(self.repTravail) + + if retour!=None: + self.encadre(retour,nouveauDepart="non") + return + + # ouverture de la trace + + self.cadreVide() + self.ajoutLigne(_("Décompacte la vidéo")) + + # décompactage : extraction de toutes les photos : + self.extensionChoisie = ".JPG" # ou png + if self.lanceFfmpeg(video)==-1: # sous les noms : "\Im_0000_%5d_Ok"+self.extensionChoisie %5d = 5 chiffres décimaux + self.encadre(_("L'outil ffmpeg est absent.") + "\n" + _("Il convient de l'associer.") ,nouveauDepart='non') + return + + self.photosAvecChemin = [x for x in os.listdir(self.repTravail) if self.extensionChoisie in str(x) and os.path.isfile(x)] # listes des photos conservées + self.photosSansChemin = list([os.path.basename(x) for x in self.photosAvecChemin]) # liste des noms de photos copiès, sans le chemin. [tuple] + + if self.photosSansChemin.__len__()==0: + self.encadre(_("Aucune image décompactée : consulter la trace.")) + self.ecritureTraceMicMac() # on écrit les fichiers trace + return + + # ajout de l'exif : + + self.ajoutExifGoPro() + + self.etatDuChantier = 2 + # Type de chantier : c'est une liste de string (on pourrait aussi mettre un dictionnaire), avec : + # [0] = s'il s'agit de 'photos' ou d'une 'vidéo' + # [1] = s'il s'agit d'un chantier 'initial' ou 'renommé' + # [2] = 'original' ou "importé" + self.typeDuChantier [0] = 'vidéo' + self.copierParamVersChantier() # effectue d'abord sauveparam() + self.ecritureTraceMicMac() # on écrit les fichiers trace + + # charge les options pour Tapioca : les valeurs d'échelle et de Line sont celles par défaut + + self.modeTapioca.set('Line')# Mode (All, MulScale, Line) + + # charge les options pour Tapas : + + self.modeCheckedTapas.set('FishEyeBasic') + + # Message final : + + self.encadre(_("Les images de la video sont décompactées sous le répertoire :") + "\n\n" + self.repTravail+ + "\n\n" + _("Il y a %s images décompactées.") % (str(self.photosSansChemin.__len__())) + + "\n\n" + _("Lancer 'Sélection des images' pour sélectionner %s images par seconde de film.") % (self.goProNbParSec.get())+ + "\n\n" + _("La sélection choisira les 'meilleures' images")+ + "\n\n" + _("Les options Tapioca et Tapas ont été positionnées pour des images GoPro : modifier si besoin")) + + return # fin : on a obtenu les photos avec un exif à partir d'une vidéo + + + + def ajoutExifGoPro(self): + + # mise à jour de l'exif des images décompactées : + + self.ajoutLigne(_("met à jour l'exif des JPG décompactés :") + "\n"+ + "F35="+self.goProFocale35.get()+"\n"+ + "F="+self.goProFocale.get()+"\n"+ + "Model="+self.goProNomCamera.get()+"\n"+ + "Make="+self.goProMaker.get()) + +## # pour format png +## if self.extensionChoisie=="png": +## setExif = [self.mm3d, +## "SetExif", +## ".*"+self.extensionChoisie, +## "F35="+self.goProFocale35.get(), +## "F="+self.goProFocale.get(), +## "Cam="+self.goProNomCamera.get()] + # pour format jpg + if self.extensionChoisie.upper()==".JPG": + setExif = [self.exiftool, + "-Make="+self.goProMaker.get(), + "-Model="+self.goProNomCamera.get(), + "-FocalLength="+self.goProFocale.get(), + "-FocalLengthIn35mmFormat="+self.goProFocale35.get(), + "*"+self.extensionChoisie] + + self.lanceCommande(setExif) + + # SetExit crée des copies "original" des fichiers initiaux, on les supprime ; + + [supprimeFichier(x) for x in os.listdir(self.repTravail) \ + if os.path.splitext(x)[1]!=self.extensionChoisie \ + and os.path.splitext(x)[0] not in self.photosSansChemin] + + def selectionGoPro(self): + + if self.typeDuChantier[0]!='vidéo': + self.encadre(_("Cette sélection de photos est réservé aux chantiers vidéos"),nouveauDepart='non') + return + + # on sélectionne un nombre d'image à la seconde en fonction de la qualité des images + + ################## Bizarrerie (bogue) : l'extension doit être png, même si le format est jpg################## + [os.rename(a,os.path.splitext(a)[0]+".png") for a in os.listdir(self.repTravail) if self.extensionChoisie in a] + ######################################################## + self.cadreVide() # ouvre la trace + self.ajoutLigne(_("Sélection d'un sous ensemble des images GoPro décompactées.")) + div = [self.mm3d, + "DIV", + "Im_0000_.*png", + "Rate="+self.goProNbParSec.get()] + self.lanceCommande(div) + + ################## Bizarrerie (bogue) : l'extension doit être png, même si le format est jpg################## + [os.rename(a,os.path.splitext(a)[0]+self.extensionChoisie) for a in os.listdir(self.repTravail) if 'png' in a] + ######################################################## + + # on supprime les intrus (les noms des fichiers intrus ont été marqué d'un N1, les autres d'un _Ok + self.ajoutLigne("\n".join([(_(" a supprimer : ")+x) for x in os.listdir(self.repTravail) if "Nl" in str(x)])) + + nbSuppressions = [supprimeFichier(x) for x in os.listdir(self.repTravail) if "Nl" in str(x)].__len__() + self.photosAvecChemin = [x for x in os.listdir(self.repTravail) if self.extensionChoisie in str(x) and os.path.isfile(x)] # listes des photos conservées + self.photosSansChemin = list([os.path.basename(x) for x in self.photosAvecChemin]) # liste des noms de photos copiès, sans le chemin. [tuple] + self.etatDuChantier = 2 + self.ecritureTraceMicMac() # on écrit les fichiers trace + if nbSuppressions==0: + self.encadre(_("Aucune sélection effectuée. La version de micmac ne propose peut-être pas cette fonction.") + "\n" + _("Consulter la trace.") + "\n\n" + _("Vous pouvez utiliser le menu 'outils/qualité des photos line'") + "\n" + _("puis effectuer une sélection manuelle."),nouveauDepart="non") + else: + self.afficheEtat(_("Images sélectionnées.") + "\n\n" + _("Vous pouvez lancer Micmac.")) + + ###################### Sélection des meilleures JPG (futur) + + def selectionJPG(self): + + if self.typeDuChantier[0]!='photos': + self.encadre(_("Cette sélection de photos est réservé aux chantiers photos"),nouveauDepart='non') + return + + # on sélectionne un nombre d'image à la seconde en fonction de la qualité des images + + ################## Bizarrerie (bogue) : l'extension doit être png, même si le format est jpg################## + [(os.rename(a,os.path.splitext(a)[0]+".png")) for a in os.listdir(self.repTravail) if self.extensionChoisie in a] + ######################################################## + self.cadreVide() # ouvre la trace + self.ajoutLigne(_("Sélection d'un sous ensemble des images GoPro décompactées.")) + + div = [self.mm3d, + "DIV", + "DSC.*png", + "Rate="+self.goProNbParSec.get()] + self.lanceCommande(div) + + ################## Bizarrerie (bogue) : l'extension doit être png, même si le format est jpg################## + [(os.rename(a,os.path.splitext(a)[0]+self.extensionChoisie)) for a in os.listdir(self.repTravail) if 'png' in a] + ######################################################## + + # on supprime les intrus (les noms des fichiers intrus ont été marqué d'un N1, les autres d'un _Ok + self.ajoutLigne("\n".join([(_(" a supprimer : ")+x) for x in os.listdir(self.repTravail) if "Nl" in str(x)])) + + nbSuppressions = [supprimeFichier(x) for x in os.listdir(self.repTravail) if "Nl" in str(x)].__len__() + self.photosAvecChemin = [x for x in os.listdir(self.repTravail) if self.extensionChoisie in str(x) and os.path.isfile(x)] # listes des photos conservées + self.photosSansChemin = list([os.path.basename(x) for x in self.photosAvecChemin]) # liste des noms de photos copiès, sans le chemin. [tuple] + self.etatDuChantier = 2 + self.ecritureTraceMicMac() # on écrit les fichiers trace + if nbSuppressions==0: + self.encadre(_("Aucune sélection effectuée.") + "\n" + _("Consulter la trace.") + "\n\n" + _("Vous pouvez utiliser le menu 'outils/qualité des photos line'\npuis effectuer une sélection manuelle."),nouveauDepart="non") + else: + self.afficheEtat(_("Images sélectionnées.") + "\n\n" + _("Vous pouvez lancer Micmac.")) + + + # ------------------ ffmpeg : extraction images d'une video ----------------------- + + def lanceFfmpeg(self,video): + + if os.path.exists(self.ffmpeg)==False: + return -1 + # Si on a un masque 3D on l'utilise et on ne cherche pas plus loin : + ffmpeg = [self.ffmpeg, + "-i", + video, + self.repTravail+"\Im_0000_%5d_Ok"+self.extensionChoisie] + self.lanceCommande(ffmpeg, + filtre=self.filtreFfmpeg, + info=_("ATTENTION : cette procédure est longue : patience !")) + + def filtreFfmpeg(self,ligne): + #if ligne[0:5]=="frame": + return ligne + + +########################################## Outils divers (raccourcis clavier, infobulle, afficher un dico de points....) + def lettre(self,event): if event.char.isdigit(): # sinon on annule la recherche digit = chiffre self.cherche = self.cherche+event.char @@ -4545,14 +8201,14 @@ def lettre(self,event): trouve = True break if trouve: - self.invitePhotoMessage.set(self.invitePhotoMessageInitial+"\nTrouvé : "+self.cherche) + self.invitePhotoMessage.set(self.invitePhotoMessageInitial+"\n" + _("Trouvé : ")+self.cherche) else: - self.invitePhotoMessage.set(self.invitePhotoMessageInitial+"\nNon trouvé : "+self.cherche) + self.invitePhotoMessage.set(self.invitePhotoMessageInitial+"\n" + _("Non trouvé : ")+self.cherche) else: self.cherche=str() self.invitePhotoMessage.set(self.invitePhotoMessageInitial) - def poll(self): # boucle srutant la valeur sélectionnée en cours, 10 fois par seconde + def poll(self): # boucle scrutant la valeur sélectionnée en cours, 10 fois par seconde try: now = self.selectionPhotos.curselection() if now != self.current: @@ -4564,9 +8220,11 @@ def poll(self): # bo def list_has_changed(self, selection): if len(selection)>0: self.current = selection - if self.retailleEtAffichePhoto(self.listeChoisir[selection[0]])=="KO": # prend l'image, la retaille et l'affiche - if self.messageSiPasDeFichier==1: - self.infoBulle(" Pas de fichier pour "+os.path.basename(self.listeChoisir[selection[0]])) # message si pas de photo + try: + if self.retailleEtAffichePhoto(self.listeChoisir[selection[0]])=="KO": # prend l'image, la retaille et l'affiche + if self.messageSiPasDeFichier==1: + self.infoBulle(_(" Pas de fichier pour ")+os.path.basename(self.listeChoisir[selection[0]])) # message si pas de photo + except: pass self.selectionPhotos.see(self.current) def infoBulle(self,texte=""): # affiche une infobulle sous le curseur. @@ -4583,9 +8241,8 @@ def infoBulle(self,texte=""): relief='solid') # texte, la taille de la fenêtre s'adapte au texte, style infobulle l.pack() self.bulle.update() - except Exception as e: - print("erreur infobulle : ",e," pour ",texte) + print(_("erreur infobulle : "),str(e)) def yview(self, *args): if args[0] == 'scroll': @@ -4615,7 +8272,8 @@ def fermerVisuPhoto(self): # fe def upDown(self,event=None): # modifie la sélection en cours après appui sur les flèches up ou Down (qui modifient seulement l'item "ACTIVE") - self.selectionPhotos.selection_clear(self.selectionPhotos.curselection()) + if self.selectionPhotos.curselection(): + self.selectionPhotos.selection_clear(self.selectionPhotos.curselection()) self.selectionPhotos.selection_set(self.selectionPhotos.index('active')) def afficherTousLesPointsDuDico(self): # affiche les points de l'imager en cours sur le canvas en cours @@ -4631,12 +8289,22 @@ def afficherTousLesPointsDuDico(self): # af nbpts+=1 if nbpts==0: - self.infoBulle("Aucun point placé sur cette photo") + self.infoBulle(_("Aucun point placé sur cette photo")) if nbpts==1: - self.infoBulle("Un point placé sur cette photo") + self.infoBulle(_("Un point placé sur cette photo")) if nbpts>1: - self.infoBulle(nbpts.__str__()+" points placés sur cette photo") - + self.infoBulle(nbpts.__str__()+_(" points placés sur cette photo")) + + def afficherLesInfosBullesDuDico(self): + if self.dicoInfoBullesAAfficher==None: + return + for e in self.dicoInfoBullesAAfficher: + if os.path.basename(e)==self.enCours: + message = str(self.dicoInfoBullesAAfficher[e]) + if message!=str(): + self.infoBulle(message) + + def xyJPGVersCanvas(self,xJPG,yJPG,bouton=None): # xJPG,yJPG : position dans l'image originale (Jpeg) couleurTexte = 'black' xFrame = xJPG * self.scale # xFrame,yFrame : position dans l'image dans le cadre @@ -4645,12 +8313,14 @@ def xyJPGVersCanvas(self,xJPG,yJPG,bouton=None): # xJPG, self.canvasPhoto.create_oval(xFrame-5, yFrame-5,xFrame+5, yFrame+5,fill='yellow',tag=bouton) ######################################## Retaille et Affiche : prépare une photo pour affichage dans une petite fenêtre 200*200 max + # attention : appelle afficherTousLesPointsDuDico et afficherLesInfosBullesDuDico qui nécessitent des variables existantes def retailleEtAffichePhoto(self,photo): # charge le canvas self.canvasPhoto - if not os.path.exists(photo): # erreur de paramètrage + self.enCours = os.path.basename(photo) + + if not os.path.exists(photo): # erreur de paramétrage try: self.canvasPhoto.delete(self.imgTk_id) # supprimer la photo dans le canvas si elle existe - except: pass - return "KO" + except: return "KO" self.dimMaxiCanvas = 200 self.hauteurCanvas = 200 self.largeurCanvas= 200 @@ -4667,13 +8337,17 @@ def retailleEtAffichePhoto(self,photo): self.img = self.imagePhoto.resize((self.largeurCanvas,self.hauteurCanvas)) self.imgTk = ImageTk.PhotoImage(self.img) self.imgTk_id = self.canvasPhoto.create_image(0,0,image = self.imgTk,anchor="nw") # affichage effectif de la photo dans canvasPhoto - self.enCours = os.path.basename(photo) + + #affichage des info bulles + try: self.bulle.destroy() + except: pass + self.afficherLesInfosBullesDuDico() self.afficherTousLesPointsDuDico() ############################### Choix d'un répertoire dans la liste des répertoires de travail, avec scrollbar : charge self.selectionPhotosAvecChemin - def choisirUnRepertoire(self,titre,mode='single'): # mode="single" ou 'extended' - self.retourChoixRepertoire="Abandon" + def choisirUnChantier(self,titre,mode='single'): # mode="single" ou 'extended' + self.retourChoixRepertoire=_("Abandon") self.fichierProposes = list() chantierSansParametre = list() for e in self.tousLesChantiers: # suppression des répertoires inexistants (parce que supprimés) @@ -4685,7 +8359,7 @@ def choisirUnRepertoire(self,titre,mode='single'): # mode="single" chantierSansParametre.insert(0,e) if len(self.fichierProposes)==0: - return "Aucun chantier mémorisé." + return _("Aucun chantier mémorisé.") self.selectionRepertoireAvecChemin=str() self.topRepertoire = tkinter.Toplevel() self.topRepertoire.title(titre) @@ -4693,10 +8367,10 @@ def choisirUnRepertoire(self,titre,mode='single'): # mode="single" fenetreIcone(self.topRepertoire) f = self.topRepertoire #ttk.Frame(self.topRepertoire) frameSelectRep = ttk.Frame(self.topRepertoire) - invite = ttk.Label(self.topRepertoire,text="Choisir le chantier à ouvrir :") + invite = ttk.Label(self.topRepertoire,text=_("Choisir le chantier à ouvrir :")) invite.pack(pady=10,padx=10,ipadx=5,ipady=5) - scrollbarV = ttk.Scrollbar(frameSelectRep, orient='vertical') - scrollbarH = ttk.Scrollbar(frameSelectRep, orient='horizontal') + scrollbarV = ttk.Scrollbar(frameSelectRep, orient=_('vertical')) + scrollbarH = ttk.Scrollbar(frameSelectRep, orient=_('horizontal')) self.selectionRepertoire = tkinter.Listbox(frameSelectRep, selectmode=mode, xscrollcommand=scrollbarH.set, @@ -4716,13 +8390,13 @@ def choisirUnRepertoire(self,titre,mode='single'): # mode="single" self.selectionRepertoire.pack(side='left', fill='both', expand=1) frameSelectRep.pack() self.selectionRepertoire.select_set(0) - b = ttk.Button(f,text="Ouvrir",command=self.validRepertoire) + b = ttk.Button(f,text=_("Ouvrir"),command=self.validRepertoire) b.pack(pady=5) - c = ttk.Button(f,text="Annuler",command=self.cancelRepertoire) + c = ttk.Button(f,text=_("Annuler"),command=self.cancelRepertoire) c.pack(pady=5) if len(chantierSansParametre)>0: - d = ttk.Label(f,text="Il y a des chantiers incomplets,\n le fichier "+self.fichierParamChantierEnCours+" est absent.\n"+ - "Ces chantiers ne peuvent être ouverts mais peuvent être supprimés :\n\n"+"\n".join(chantierSansParametre)) + d = ttk.Label(f,text=_("Il y a des chantiers incomplets,") + "\n" + _(" le fichier %s est absent.") % (self.paramChantierSav)+ "\n" + + _("Ces chantiers ne peuvent être ouverts mais peuvent être supprimés :") + "\n\n"+"\n".join(chantierSansParametre)) d.pack(pady=5) fenetre.wait_window(self.topRepertoire) return self.retourChoixRepertoire @@ -4747,47 +8421,642 @@ def validRepertoire(self): def cancelRepertoire(self): self.topRepertoire.destroy() - self.retourChoixRepertoire="Abandon utilisateur." + self.retourChoixRepertoire=_("Abandon utilisateur.") - def envPath(self): - return + ############################## Répertoire Orientation en cours ou futur et répertoire des points Homologues - def orientation(self): # définit le répertoire qui contient l'orientation la plus récente : - # soit Arbitrary soit echelle3d soit bascul + def orientation(self): # définit le répertoire qui contient l'orientation la plus récente : + # soit Arbitrary aprés tapas(même si absent) soit echelle3 aprés calibration par axe, plan et métrique + # soit bascul aprés calibration par points GPS - if os.path.exists(os.path.join(self.repTravail,"Ori-bascul")): + if os.path.exists(os.path.join(self.repTravail,"Ori-bascul")): # orientation obtenue aprés Tapas et GCPbascule (points GPS OK) return "bascul" - - if os.path.exists(os.path.join(self.repTravail,"Ori-echelle3")): - orientation = "echelle3" + + if os.path.exists(os.path.join(self.repTravail,"Ori-echelle3")): # # orientation obtenue aprés Tapas et calibration (points GPS OK) return "echelle3" - + return "Arbitrary" + ########## pour renommer homol + + def repertoireHomol(self,homol): + # le paramètre permet d'utiliser un autre répertoire + try: os.rename(_("Homol"),_("HomolTemporaire")) + except Exception as e: + print(_("erreur renommage Homol en HomolTemporaire : "),str(e)) + return + try: + os.rename(homol,_("Homol")) + self.homolActuel = homol # Pour retourner à la situation originale si besoin + except Exception as e: print(_("erreur renommage %s en Homol : ") % (homol),str(e)) + + + def retourHomol(self): # pour l'instant inutilisé + + if self.homolActuel==str(): return + try: os.rename(_("Homol"),self.homolActuel) + except Exception as e: + print(_("erreur renommage Homol en : %s : ") % (self.homolActuel),str(e)) + return + try: os.rename(_("HomolTemporaire"),"Homol") + except Exception as e: + print(_("erreur renommage HomolTemporaire en Homol : "),str(e)) + return + self.homolActuel = str() + + #################### Examen du nombre de points homologues dans le répertoire homol sous le répertoire passé en paramètre, affichage + + def nombrePointsHomologues(self,repertoire=""): + self.menageEcran() + cas = str() + if repertoire=="": + repertoire = self.repTravail + cas = _("dernier traitement : ")+self.modeTapioca.get() + elif "All" in repertoire: + cas = "MulScale All " + self.echelle1.get() + elif "Line" in repertoire: + cas = "Line "+self.echelle4.get()+" "+self.delta.get() + + repertoireHomol = os.path.join(repertoire,"Homol") # répertoire des homologues + if os.path.isdir(repertoireHomol)==False and repertoire==self.repTravail: + self.encadre(_("Lancer MicMac avant de pouvoir évaluer la qualité des photos."),nouveauDepart='non') + return + if os.path.isdir(repertoireHomol)==False and repertoire!=self.repTravail: + self.encadre(_("Le traitement n'a donné aucun point homologue.") + "\n\n" + _("Consulter la trace."),nouveauDepart='non') + return + + #somme des scores de chaque photo : préparation des données + homol = dict() + nb = dict() + moyenne = dict() + for photo in self.photosSansChemin: + homol[photo] = 0 # nombre total des points homologue de l'image + nb[photo] = 0 # nombre d'images "comparées" + + + os.chdir(repertoireHomol) + nbPoints = 0 + for e in os.listdir(): # balaie tous les fichiers contenant les points homologues + os.chdir(os.path.join(repertoireHomol,e)) + for f in os.listdir(): + if os.path.isfile(f): # fichier : on calcule le nombre de points homologues dans le fichier + nbPoints = 0 + if f[-3:]=="dat": + taille = os.path.getsize(f) + nbPoints = (taille-8)/44 # fichier binaire + if f[-3:]=="txt": # fichier texte + with open(f) as infile: # il faut lire de fichier (longueur variable) + nbPoints = infile.readlines().__len__() + for photo in self.photosSansChemin: + if photo in e: + homol[photo] += nbPoints + nb[photo] += 1 + moyenne[photo] = homol[photo]/nb[photo] + + + #on crée le rapport : nombre moyen de points homologues, trié du + grand au plus petit : dans ajouLigne + + listeHomol = list(moyenne.items()) + listeHomol.sort(key=lambda e: e[1],reverse=True) + self.effaceBufferTrace() # efface ajoutligne + self.ajoutLigne("\n" + _("Classement des photos par nombre de points homologues :") + "\n\n"+cas+"\n\n") + self.ajoutLigne(chr(9)+_("Photo")+chr(9)+chr(9)+_("score")+chr(9)+_("nb photos en correspondance") + "\n\n") + + for e in listeHomol: + self.ajoutLigne(e[0]+chr(9)+chr(9)+str(int(e[1]))+chr(9)+chr(9)+str(nb[e[0]])+"\n") + + if len(listeHomol)==0: + self.ajoutLigne(_("Aucune photo n'a de point analogue avec une autre.") + "\n") + + self.ajoutLigne("\n"+heure()+_(" : fin de la recherche sur la qualité des photos.")) + self.ajoutLigne("\n\n ******") + ligneFiltre = self.ligneFiltre # l'écriture de la trace efface self.ligneFiltre et encadre doit être en fin de paragraphe + self.ecritureTraceMicMac() + os.chdir(self.repTravail) + self.encadre(ligneFiltre,nouveauDepart='non') + +################## Sélection des N meilleures photos en fonction de leur nombre de points homologues.... +################## remarque : on sélectionne les meilleurs couples, avec un petit effort sur le premier item des éléments de listeTaille +################## Attention : suppose que les points homologues soient dans des fichiers .dat ( si variable self.exptxt="0") sinon des .txt + + def lesMeilleuresPhotos(self,nombre=0): # retourne la liste des N = nombre meilleures photos en nombre de points homologues. + self.menageEcran() + listeTaille = list() + repertoireHomol = os.path.join(self.repTravail,"Homol") # répertoire des homologues + if os.path.isdir(repertoireHomol)==False: + self.encadre(_("Lancer d'abord Tapioca/Tapas")) + return + + os.chdir(repertoireHomol) + for e in os.listdir(): # balaie tous les fichiers contenant les points homologues + os.chdir(os.path.join(repertoireHomol,e)) + for f in os.listdir(): + listeTaille.append((e,f, os.path.getsize(f))) # répertoire, nom du fichier et taille + os.chdir(self.repTravail) + + listeTaille.sort(key= lambda e: e[2],reverse=True) # trie la liste des fichiers par taille + if self.exptxt =="0" : typeFichier=".dat" + if self.exptxt =="1" : typeFichier=".txt" + liste = [(e[1].split(typeFichier)[0],e[0].split("Pastis")[-1]) for e in listeTaille] # liste des noms des plus gros fichiers des fichiers de l'arborescence Homol + listeSet=set() # chaque nom peut apparaitre plusieurs fois : on va utilsier un ensemble (set) + for e in liste : # on ne conserve que les n premiers + listeSet.add(e[0]) # ajout nom du répertoire = premiere photo(la lecture de la liste conserve l'ordre des tailles) + listeSet.add(e[1]) # ajout seconde photo + if len(listeSet)>=nombre: # le passage par un ensemble fait perdre l'ordre des tailles (sans importance : on ne retient que les meilleures) + break + listeOk = [e for e in listeSet if os.path.exists(e)] # liste limitée aux fichiers effectivement présents sous le répertoire de travail + return listeOk + +#################### Lister les fichiers Ply générés: + + def lister3DPly(self): + listePly = [e for e in os.listdir() if os.path.splitext(e)[1]==".ply"] + if listePly==list(): + self.encadre(_("Aucun nuage de points dans ce chantier."),nouveauDepart='non') + return + self.choisirUnePhoto(listePly, + titre=_("Liste des nuages de points du chantier"), + message=_("les nuages (fichiers ply) :"), + messageBouton=_("Visualiser"), + boutonDeux=_("Fermer"), + mode='single') + if self.selectionPhotosAvecChemin.__len__()==1: + self.lanceCommande([self.meshlab,self.selectionPhotosAvecChemin[0]],attendre=False) + + #################### Fusionner des fichiers Ply : + + def choisirPuisFusionnerPly(self): + + listePly = [e for e in os.listdir() if os.path.splitext(e)[1]==".ply"] + if listePly==list(): + self.encadre(_("Aucun nuage de points dans ce chantier."),nouveauDepart='non') + return + self.choisirUnePhoto(listePly, + titre=_("Fusion de nuages"), + message=_("Choisir les fichiers à fusionner :"), + messageBouton=_("Fusionner et visualiser"), + boutonDeux=_("Fermer"), + mode='extended') + if self.selectionPhotosAvecChemin.__len__()==0: + return + if self.selectionPhotosAvecChemin.__len__()==1: + self.encadre(_("Choisir au moins 2 nuages pour la fusion."),nouveauDepart='non') + return + liste = "|".join([os.path.splitext(os.path.basename(x))[0] for x in self.selectionPhotosAvecChemin]) + self.mergePly = 'fusion.ply' + i = 0 + while os.path.exists(os.path.join(self.repTravail,self.mergePly))==True and i<20: + i+=1 + self.mergePly = 'fusion_'+str(i)+".ply" + self.fusionnerPly(self.selectionPhotosAvecChemin,self.mergePly) + + def fusionnerPly(self,liste,nomFinal): + + if liste.__len__()==0: + return + if liste.__len__()==1: + self.encadre(_("Choisir au moins 2 nuages pour la fusion."),nouveauDepart='non') + return + if os.path.exists(liste[0])==False or os.path.exists(liste[1])==False: # la liste comprend au moins 2 fichiers : existent-t-ils ? + self.encadreEtTrace(_("Les ply attendus n'ont pas été créé.") + "\n" + _("Consulter la trace.")) + return + + supprimeFichier(nomFinal) # tentative de suppression du fichier résultat + # on va fusionner tous les ply, on dénomme ceux qui ne doivent pas l'être : + [os.rename(e,os.path.splitext(e)[0]+".pyl") for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]=='.ply' and e not in liste] # pour ne traiter que le nécessaire (self.photosCalibrationSansChemin) + + mergePly = [self.mm3d, + "mergeply", + '.*.ply', + "Out="+nomFinal] + self.lanceCommande(mergePly) # fusion des ply : attention si types différents (xyz,xyzrgb), plante + [os.rename(e,os.path.splitext(e)[0]+".ply") for e in os.listdir(self.repTravail) if os.path.splitext(e)[1]==".pyl"] # remise à l'état initial + if os.path.exists(nomFinal): + self.lanceCommande([self.meshlab,nomFinal],attendre=False) + self.encadreEtTrace(_("Nuage fusionné :") + "\n\n" + nomFinal + "\n\n" + _("ajouté à la liste des nuages.") + "\n" + _("résultat de la fusion de :") + "\n\n" + +"\n"+"\n".join(liste)+"\n") + else: + self.encadreEtTrace(_("La fusion n'a pu se réaliser.") + "\n" + _("Consulter la trace.")) + ################### Indices surfaciques ################################ + + def afficheSurf(self): + self.majParametre() + while(1): + try: + float(self.pas_maillage.get()) + break + except: + self.encadre(_("Saisir une valeur numérique")) + time.sleep(1) + self.majParametre() + pas = float(self.pas_maillage.get()) + methode_interpolation = self.methode_interpol.get() + + self.encadre(_("Passage en coordonnées xyz")) + traite = Ply2XYZ() + self.encadre(_("Création de la grille ...")) + grid._set_nom(traite.fname_out()) + grid.affiche_grille(methode_interpolation,pas) + self.encadre(_("Création de la grille ...")) + + def calculIndices(self): + self.majParametre() + while(1): + try: + float(self.pas_maillage.get()) + break + except: + self.encadre(_("Saisir une valeur numérique")) + time.sleep(1) + self.majParametre() + pas = float(self.pas_maillage.get()) + methode_interpolation = self.methode_interpol.get() + + self.encadre(_("Passage en coordonnées xyz")) + traite = Ply2XYZ() + self.encadre(_("Création de la grille ...")) + grid._set_nom(traite.fname_out()) + grille_reg = grid.creer_grille(methode_interpolation, pas) + grid.sauvegarder_grille(traite, grille_reg,pas) + + # Calculs + + donnee._set_nom(grid.nomFichier_sortie(traite,pas)) + self.encadre(_("Le calcul peut durer quelques minutes ...")) + rugosite = donnee.ecart_type() + res_tortuosite = donnee.tortuosity(pas) + tortuosite = res_tortuosite[0] + ecarType = res_tortuosite[1] + cles = res_tortuosite[2] + self.encadre(_("Rugosité moyenne quadratique : ") + str.format('{0:.3f}',rugosite[0]) +" +/- " +str.format('{0:.3f}',rugosite[1])+ + "\r\n " + _("Tortuosité moyenne : ") + str.format('{0:.3f}',tortuosite) +" +/- " +str.format('{0:.3f}',ecarType)+ + "\n " + _("nombre de profils utilisés : ") + str(len(cles))+ + "\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])+"") + + self.majAffiche_profil() + while( self.affOK()): + while(1): + try: + int(self.num_profil.get()) + if(int(self.num_profil.get()) not in range(cles[-1]-cles[0]+1)): + self.encadre(_("Choisir une valeur valide ")+ + "\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])+"\r\n") + self.majAffiche_profil() + else: + break + except: + self.encadre(_("Saisir une valeur numérique")) + time.sleep(1) + self.encadre("\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])) + self.majAffiche_profil() + id_profil = int(self.num_profil.get()) + donnee.affiche_profil(cles[id_profil], pas) + + def calculPmp(self): + self.majParametre() + while(1): + try: + float(self.pas_maillage.get()) + break + except: + self.encadre(_("Saisir une valeur numérique")) + time.sleep(1) + self.majParametre() + pas = float(self.pas_maillage.get()) + methode_interpolation = self.methode_interpol.get() + + self.encadre(_("Passage en coordonnées xyz")) + traite = Ply2XYZ() + self.encadre(_("Création de la grille ...")) + grid._set_nom(traite.fname_out()) + grille_reg = grid.creer_grille(methode_interpolation, pas) + grid.sauvegarder_grille(traite, grille_reg,pas) + donnee._set_nom(grid.nomFichier_sortie(traite,pas)) + self.encadre(_("Le calcul peut durer quelques minutes ...")) + res_pmp = donnee.pmp() + prof_mDeprofil = res_pmp[0] + cles = res_pmp[2] + self.encadre(_("Profondeur moyenne de profil (moyenne) : ") + str.format('{0:.3f}',prof_mDeprofil) + " +/- " +str.format('{0:.3f}',res_pmp[1])+ + "\n" + _("Profondeur de texture équivalente : ")+ str.format('{0:.3f}',0.8*prof_mDeprofil+0.2)+ " +/- " +str.format('{0:.3f}',.8*res_pmp[1]+0.2)+ + "\n " + _("nombre de profils utilisés : ")+str(len(cles))+ + "\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])+"") + + self.majAffiche_profil() + while( self.affOK()): + while(1): + try: + int(self.num_profil.get()) + if(int(self.num_profil.get()) not in range(cles[-1]-cles[0]+1)): + self.encadre(_("Choisir une valeur valide ") + + "\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])+"\r\n") + self.majAffiche_profil() + else: + break + except: + self.encadre(_("Saisir une valeur numérique")) + time.sleep(1) + self.encadre("\n " + _("id profil entre : ")+str(0)+"-"+str(cles[-1]-cles[0])) + self.majAffiche_profil() + id_profil = int(self.num_profil.get()) + donnee.affiche_profil(cles[id_profil], pas) + + ################### Conversion au format jpg, information de l'Exif + + def conversionJPG(self,liste=list()): + + if self.pasDeConvertMagick(): + self.ajoutLigne(_("Le programme de conversion n'est pas présent.")) + return + if liste==list(): + liste = self.photosSansChemin + if liste.__len__()==0: + return + curdir = os.getcwd() + os.chdir(os.path.dirname(liste[0])) + for e in liste: + if os.path.isfile(e): + i=os.path.basename(e) + nouveauJPG = os.path.splitext(i)[0]+".JPG" + convert = [self.convertMagick,i,'-quality 100',nouveauJPG] + print(convert) + os.system(" ".join(convert)) + os.chdir(curdir) + + # mise à jour des paramètres de surfaces + def majParametre(self): + self.menageEcran() + self.item7000.pack() + self.item7000.mainloop() + + + def surfOK(self): + self.item7000.pack_forget() + self.encadreEtTrace(_("Paramètres mis à jour") + "\n"+ + _("Méthode = ")+self.methode_interpol.get()+"\n"+ + _("Pas du maillage = ")+self.pas_maillage.get()+"\n") + self.item7000.quit() + return + + def surfKO(self): + self.item7000.pack_forget() # pour éviter la question par menageEcran + self.afficheEtat() + + # paramètre d'affichage d'un profil (Indices surfaciques) + + def majAffiche_profil(self): + self.item8000.pack() + self.item8000.mainloop() + + def affOK(self): + self.item8000.quit() + return True + + def affK0(self): + self.item8000.pack_forget() # pour éviter la question par menageEcran + self.afficheEtat() + + # mise à jour de l'exif : + + def majExif(self,liste=list()): + if self.pasDeExiftool():return + self.menageEcran() + self.OutilAppareilPhoto(silence='oui') + self.menageEcran() + self.exifMaker.set(self.fabricant) + self.exifNomCamera.set(self.nomCamera) + self.exifFocale.set(self.focale) + self.exifFocale35.set(self.focale35MM) + self.item3000.pack() + return + + def exifOK(self): + if self.pasDeExiftool():return + listeTag = [('Make', self.exifMaker.get() ), + ('Model', self.exifNomCamera.get() ), + ('FocalLength', self.exifFocale.get() ), + ('FocalLengthIn35mmFormat', self.exifFocale35.get() ) + ] + + + self.informerExif(self.exiftool,self.photosSansChemin,listeTag) + self.item3000.pack_forget() # pour éviter la question par menageEcran + self.encadreEtTrace(_("Exifs mis à jour") + "\n"+ + _("Fabricant = ")+self.exifMaker.get()+"\n"+ + _("Modèle = ")+self.exifNomCamera.get()+"\n"+ + _("Focale = ")+self.exifFocale.get()+"\n"+ + _("Focale eq 35mm = ")+self.exifFocale35.get()+"\n") + self.pasDeFocales = False # raz self.pasDeFocales + + def exifKO(self): + self.item3000.pack_forget() # pour éviter la question par menageEcran + self.encadre(_("Abandon de la mise à jour des exifs"),nouveauDepart="non") + + + # Aprés saisie de l'exif : + + def informerExif(self,exiftool,listeFichiers,listeTagInfo): # la liste peut être relative ou absolue, taginfo est une liste de tuple (tag,info) + + if self.pasDeExiftool():return + + if listeFichiers.__len__()==0: + return _("Aucune photo à mettre à jour.") + + if self.nombreDExtensionDifferentes(listeFichiers)!=1: + return _("La liste des fichiers comporte plusieurs extensions différentes : abandon.")+\ + "\n".join(listeFichiers) + + extension = os.path.splitext(listeFichiers[0])[1] + if extension.upper() not in ".JPG.JPEG": + interface.encadre(_("La version actuelle ne traite que les exif des photos au format JPG, or le format des photos est %s. Désolé, abandon.") % (extension) ) + return + + # Controle de l'existence des fichiers : + for e in listeFichiers: + if os.path.isfile(e)==False: + return _("Le fichier %s n'existe pas. Abandon") % (e) + + # mise à jour de l'exif des images décompactées : + + message = _("met à jour l'exif de ")+"\n".join(listeFichiers)+"\n" + + # Les fichiers sont ok on va pouvoir les traiter : + + listeModifs = ["-"+tag+"="+info for tag,info in listeTagInfo] + + # pour format jpg + + setExif = [exiftool]+listeModifs+["-ext .JPG", self.repTravail] # ["*"+extension] + + self.lanceCommande(setExif) + + # SetExit crée des copies "original" des fichiers initiaux, on les supprime ; + + [supprimeFichier(x) for x in os.listdir(self.repTravail) \ + if os.path.splitext(x)[1]!="."+extension \ + and os.path.splitext(x)[0] in listeFichiers] + + return "" + + + #################### Utilitaires : tests de la présence de photos, de mm3d, d'exiftool, envoi retour chariot et compte le nombre d'extensions différentes dans une list + def pasDePhoto(self): - if self.photosPropresAvecChemin.__len__()==0: - self.encadre("Choisir des photos au préalable.",nouveauDepart="non") + if self.photosAvecChemin.__len__()==0: + self.encadre(_("Choisir des photos au préalable."),nouveauDepart="non") return True - liste = [e for e in self.photosPropresAvecChemin if os.path.exists(e)==False] + liste = [e for e in self.photosAvecChemin if os.path.exists(e)==False] if liste.__len__()>0: - texte="Attention les photos suivantes sont absentes sur disque : \n"+"\n".join(liste)+"\nElles sont supprimées." - self.photosPropresAvecChemin = liste = [e for e in self.photosPropresAvecChemin if os.path.exists(e)] - self.photosSansChemin =list([os.path.basename(x) for x in self.photosPropresAvecChemin]) + texte=_("Attention les photos suivantes sont absentes sur disque : ") + "\n"+"\n".join(liste)+"\n" + _("Elles sont supprimées.") + self.photosAvecChemin = liste = [e for e in self.photosAvecChemin if os.path.exists(e)] + self.photosSansChemin =list([os.path.basename(x) for x in self.photosAvecChemin]) repertoireInitial = os.path.dirname(self.photosAvecChemin[0]) self.photosAvecChemin = [os.path.join(repertoireInitial,e) for e in self.photosSansChemin] - self.deuxBoutons(titre="Problème de fichiers",question=texte,b1='OK',b2='') # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1 + self.troisBoutons(titre=_("Problème de fichiers"),question=texte,b1='OK',b2='') # b1 renvoie 0, b2 renvoie 1 ; fermer fenetre = -1 + def pasDeMm3d(self): + if not os.path.exists(self.mm3d): + self.encadre("\n" + _("Bonjour !") + "\n\n" + _("Commencer par indiquer où se trouve MicMac :") + "\n\n"+ + _(" - menu Paramétrage/Associer le répertoire bin de MicMac") + "\n\n"+ + _("Ensuite consulter l'aide, item 'pour commencer'.") + "\n\n"+ + _("Si besoin :") + "\n"+ + _( " - Associer convert et exiftool s'ils ne sont pas trouvés automatiquement sous micmac/binaire-aux")+"\n"+ + _(" - Associer un outil (CloudCompare ou Meshlab) pour afficher les nuages de points 3D") + "\n\n"+ + _(" - Consulter la notice d'installation et de prise en main"), + aligne='left',nouveauDepart='non') + return True + + def pasDeExiftool(self): + if not os.path.exists(self.exiftool): + self.encadre(_("Désigner le fichier exiftool (menu paramétrage)."),nouveauDepart="non") + return True + + def pasDeConvertMagick(self): + if not os.path.exists(self.convertMagick): + self.encadre(_("Désigner le fichier convert, ou avconv, d'image Magick") + "\n" + _("en principe sous micmac\\binaire-aux (menu paramétrage)."),nouveauDepart="non") + return True + def pasDeFfmpeg(self): + if not os.path.exists(self.ffmpeg): + self.encadre(_("Désigner le fichier ffmpeg (possible sous micmac\\binaire-aux (menu paramétrage)."),nouveauDepart="non") + return True + + def envoiRetourChariot(self,dest): # dest étant le processus ouvert par popen + dest.communicate(input='t\n') + + def nombreDExtensionDifferentes(self,liste): + lesExtensions=set([os.path.splitext(x)[1].upper() for x in liste]) # on vérifie l'unicité de l'extension : + self.lesExtensions=list(lesExtensions) # liste pour être slicable + return len(self.lesExtensions) +######################################################## Modifier les options par défaut + + + def majOptionsParDefaut(self): # Si les options ont déjà été modifiées + if os.path.exists(self.fichierSauvOptions): + retour = self.troisBoutons(titre=_("Modifier les options par défaut"), + question=self.messageSauvegardeOptions, + b1=_("Revenir aux options par défaut d'AperoDeDenis"), + b2=_("Utiliser les options du chantier en cours"), + b3=_("Ne rien changer")) + if retour == 0: + supprimeFichier(self.fichierSauvOptions) + self.encadre(_("Options par défaut réinitialisées")) + elif retour == 1: + optionsOK = self.sauveOptions() + if optionsOK==True: + self.encadre(_("Les options par défaut seront désormais celles du chantier en cours"),nouveauDepart='non') + else: + self.encadre(optionsOK,nouveauDepart='non') + else: + self.afficheEtat() + + else: # Si les options n'ont pas été modifiées + retour = self.troisBoutons(titre=_("Modifier les options par défaut"), + question=self.messageSauvegardeOptions+ + _("Les options par défaut actuelles sont les options par défaut d'AperoDeDenis"), + b1=_("Utiliser les options du chantier en cours"), + b2=_("Ne rien changer")) + if retour == 0: + optionsOK = self.sauveOptions() + if optionsOK==True: + self.encadre(_("Les options par défaut seront désormais celles du chantier en cours"),nouveauDepart='non') + else: + self.encadre(optionsOK,nouveauDepart='non') + else: + self.afficheEtat() + + def sauveOptions(self): + retour = self.controleOptions() + if retour!=True: + message = _("Options par défaut non sauvegardées car les options du chantier en cours sont invalides :") + "\n"+retour + return message + try: + sauvegarde3=open(self.fichierSauvOptions,mode='wb') + pickle.dump(( self.echelle1.get(), # nécessaire pour définir la variable obtenue le widget + self.echelle2.get(), + self.echelle3.get(), + self.echelle4.get(), + self.delta.get(), + self.file.get(), + self.modeTapioca.get(), + self.modeMalt.get(), + self.modeCheckedTapas.get(), + self.arretApresTapas.get(), + self.photosUtilesAutourDuMaitre.get(), + self.calibSeule.get(), + self.zoomF.get(), + self.modeC3DC.get(), + self.tawny.get(), + self.tawnyParam.get(), + version, + self.lancerTarama.get() + ), + sauvegarde3) + sauvegarde3.close() + except Exception as e: # Controle que le programme a accès en écriture dans le répertoire d'installation + print (_('erreur sauveOptions : '),str(e)) + texte = _("Erreur rencontrée lors de la sauvegarde des options : ")+str(e) + return texte + return True + + def restaureOptions(self): + if not os.path.exists(self.fichierSauvOptions): return + try: # s'il y a une sauvegarde alors on la restaure + sauvegarde4 = open(self.fichierSauvOptions,mode='rb') + r = pickle.load(sauvegarde4) + sauvegarde4.close() + self.echelle1.set(r[0]) # nécessaire pour définir la variable obtenue le widget + self.echelle2.set(r[1]) + self.echelle3.set(r[2]) + self.echelle4.set(r[3]) + self.delta.set(r[4]) + self.file.set(r[5]) + self.modeTapioca.set(r[6]) + self.modeMalt.set(r[7]) + self.modeCheckedTapas.set(r[8]) + self.arretApresTapas.set(r[9]) + self.photosUtilesAutourDuMaitre.set(r[10]) + self.calibSeule.set(r[11]) + self.zoomF.set(r[12]) + self.modeC3DC.set(r[13]) + self.tawny.set(r[14]) + self.tawnyParam.set(r[15]) + # R16 est la version d'aperodedenis, inutile pour l'instant + self.lancerTarama.set(r[17]) + except Exception as e: + print(_("erreur restauration options : ")+str(e)) + + - ######################################################## nouvelle fenêtre + ######################################################## nouvelle fenêtre (relance utile pour vider les traces d'exécution de mm3d et autres) def nouveauDepart(self): + try: self.copierParamVersChantier() # sauvegarde du chantier, des param... + except: pass + try: self.ecritureTraceMicMac() # on écrit les fichiers trace + except: pass - self.copierParamVersChantier() # sauvegarde du chantier, des param... - self.ecritureTraceMicMac() # on écrit les fichiers trace - -# faut-t-il différencier linux et windows ? +# faut-il différencier linux et windows ? if self.systeme=='posix': if self.messageNouveauDepart==str(): self.afficheEtat() @@ -4797,23 +9066,28 @@ def nouveauDepart(self): if self.systeme=='nt': global messageDepart - messageDepart = self.messageNouveauDepart - fenetre.destroy() - + messageDepart = self.messageNouveauDepart # ce message sera repris dans la nouvelle "interface" + if "fenetre" in globals(): + time.sleep(0.2) + try: + fenetre.destroy() # relance une nouvelle "interface" + except: pass + # quitter def quitter(self): texte="" if self.etatDuChantier > 2 and self.etatSauvegarde =="*": - if self.deuxBoutons("Enregistrer le chantier "+self.chantier+" ?","Chantier modifé depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?","Enregistrer","Ne pas enregistrer.") == 0: + if self.troisBoutons(_("Enregistrer le chantier %s ?") % (self.chantier), + _("Chantier modifié depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?"), + _("Enregistrer"),_("Ne pas enregistrer.")) == 0: self.copierParamVersChantier() - texte="Chantier précédent enregistré : "+self.chantier+"\n" - print(heure()+" "+texte+" fin normale d'aperodedenis.") + texte=_("Chantier précédent enregistré : %s")% (self.chantier) + "\n" + print(heure()+" "+texte+_("fin normale d'aperodedenis.")) self.sauveParam() global continuer # pour éviter de boucler sur un nouveau départ - continuer = False + continuer = False # termine la boucle mainloop fenetre.destroy() - time.sleep(0.5) ################################## FIN DE LA CLASSE INTERFACE ########################################################### @@ -4827,28 +9101,30 @@ def pv(variable): # affiche le nom de la variable, sa classe et sa valeur print('\n------------------') if '))' in stack[0][3]: nomVariable = stack[0][3].replace('pv(', '').replace('))', ')') - typeVariable = "fonction" - valeurVariable = "valeur en retour : " + typeVariable = _("fonction") + valeurVariable = _("valeur en retour : ") else: nomVariable = stack[0][3].replace('pv(', '').replace(')', '') - typeVariable = "variable" - valeurVariable = "valeur : " - print ("Détail de la "+typeVariable+" : ",nomVariable, - '\nIdentifiant : ',id(variable), - '\nType : ',type(variable), - '\nclass = ',variable.__class__, - '\nLes attributs : ',dir(variable), - '\n\n'+valeurVariable,str(variable)) + typeVariable = _("variable") + valeurVariable = _("valeur : " ) + print (_("Détail de la %(typeVar)s : %(nomVar)s") % {"typeVar" : typeVariable, "nomVar" : nomVariable}, + '\n', _('Identifiant : '),id(variable), + '\n', _('Type : '),type(variable), + '\n', _('class = '),variable.__class__, + '\n', _('Les attributs : '),dir(variable), + '\n\n')+valeurVariable,str(variable) print('\n------------------') -def heure(): # time.struct_time(tm_year=2015, tm_mon=4, tm_mday=7, tm_hour=22, tm_min=56, tm_sec=23, tm_wday=1, tm_yday=97, tm_isdst=1) - return "le "+str(time.localtime()[2])+"/"+str(time.localtime()[1])+"/"+str(time.localtime()[0])+" à "+str(time.localtime()[3])+":"+str(time.localtime()[4]) def supprimeFichier(fichier): - try: - os.remove(fichier) - except: - return + try: os.remove(fichier) + except Exception as e: + return _("Erreur suppression fichier :")+str(e) + +def supprimeMasque(repertoire,masque): + for e in os.listdir(repertoire): + if masque in e: + supprimeFichier(e) def blancAuNoir(p): if p == 255: @@ -4866,24 +9142,56 @@ def ajout(liste,item): # ajout d'un item dns un for e in c: liste.append(e) except Exception as e: - print ("erreur ajout : ",liste,"+",item," : ",e) + print (_("erreur ajout : "),str(e)) def supprimeArborescenceSauf(racine,listeSauf=list()): # supprime toute une arborescence, sauf une liste de fichiers sous la racine listeSauf = [os.path.basename(e) for e in listeSauf] - for fichier in os.listdir(racine): chemin = os.path.join(racine,fichier) if fichier in listeSauf: if os.path.isdir(chemin): - shutil.rmtree(chemin) + try: shutil.rmtree(chemin) + except: pass else: if os.path.isfile(chemin): - os.remove(chemin) + try: + os.remove(chemin) + except Exception as e: + print(_("erreur remove = "),str(e)) + return else: shutil.rmtree(chemin) # on supprime tous les sous répertoires 'calculs, temporaires...) +def zipdir(path): # path = chemin complet du répertoire à archiver, + # crée un zip qui contient tous les fichiers sauf les exports + # avec un nouveau nom de chantier = ancienNom(export) + try: + archive = os.path.join(path,os.path.basename(path)+".exp") # archive : nom du fichier dans lequel mettre l'archive + racine = os.path.dirname(path) # racine pour dezip + zipf = zipfile.ZipFile(archive, 'w') + + for root, dirs, files in os.walk(path): + for file in files: + if not os.path.splitext(archive)[1]==os.path.splitext(file)[1]: # les archives ne sont pas incluses dans le zip + fichier = os.path.join(root, file) # nom complet du fichier à archiver + cheminDezip = fichier.partition(racine)[2] # nom pour le dezippage (on change le nom du répertoire de travail relatif dans le chantier + cheminDezip = cheminDezip.replace(interface.chantier,interface.chantier+interface.suffixeExport,1) + zipf.write(fichier, + arcname=cheminDezip, + compress_type=zipfile.ZIP_DEFLATED ) + interface.encadrePlus(".") + zipf.close() + return os.path.getsize(archive) + except Exception as e: + print(_("erreur zip = "),str(e)) + return -1 + + -def afficheChemin(texte): #avant d'afficher un chemin on s'assure que le séparateur est bien le bon suivant l'OS +def afficheChemin(texte): # avant d'afficher un chemin on s'assure que le séparateur est bien le bon suivant l'OS + # normcase supprimé le 26 avril 2016 : affectait les noms de fichiers en minuscule + texte = str(texte) + texte = os.path.normpath(texte) return texte.replace(interface.separateurAutre,interface.separateurChemin) def format2Colonnes(col1,col2,largeurCol1EnPixels): @@ -4903,15 +9211,28 @@ def verifMm3d(mm3D): # Il faudrait que la version de MicMac autorise if "SaisieMasqQT" in helpMm3d: return True else: return False +def mercurialMm3d(mm3D): # Il faudrait que la version de MicMac autorise la saisie de masque en 3D, sinon ancienne version, susceptible de donner des erreurs. + if os.path.exists(mm3D)==False: return False + try: mercurialMm3d = subprocess.check_output([mm3D,"CheckDependencies"],universal_newlines=True) + except Exception as e: + print(_("erreur mercurial : %(e)s pour mm3D=%(mm3D)s") %{"mm3D" : mm3D, "e" : str(e)}) + return _("pas de version identifiée de MicMac") + else: return mercurialMm3d.splitlines()[0] + + def verifierSiExecutable(exe): try: subprocess.check_call(exe) return True - except: - return False - + except Exception as e: + try: + subprocess.check_call([exe,"-h"]) + return True + except Exception as f: + return False + def envoiRetourChariot(self,dest): # dest étant le processus ouvert par popen - dest.communicate(input='t\n') + dest.communicate(input='tn') def open_file(filename): if sys.platform == "win32": @@ -4923,13 +9244,17 @@ def open_file(filename): def fenetreIcone(fenetre=""): # Icone au format GIF pour être géré par tkinter sans utiliser Pillow if fenetre=="": - return + return photo = tkinter.PhotoImage(data=iconeTexte) fenetre.tk.call('wm', 'iconphoto', fenetre._w, photo) -def fin(codeRetour=0): - os._exit(codeRetour) - +def sizeDirectoryMO(path): + size = 0 + for root, dirs, files in os.walk(path): + for fic in files: + size += os.path.getsize(os.path.join(root, fic)) + return round(size/1000000) + '''################################## Crée un fichier contenant l'icone de l'application et en renvoie le nom conserver pour exemple de ficheir temporaire def iconeGrainSel(): @@ -4939,25 +9264,27 @@ def iconeGrainSel(): f.write(iconeBin) return f.name ''' + + ################################## Classe : Dialogue minimum modal : demande une chaine de caractères ###########################" class MyDialog: - def __init__(self,parent,titre="Nouveau nom pour le chantier : ",basDePage='none'): + def __init__(self,parent,titre=_("Nouveau nom pour le chantier : "),basDePage='none'): self.saisie=str() - top = self.top = tkinter.Toplevel(parent,width=200,relief='sunken') + top = self.top = tkinter.Toplevel(parent,width=250,relief='sunken') top.transient(parent) - top.geometry("400x250+100+100") + top.geometry("400x300+100+100") fenetreIcone(self.top) l=ttk.Label(top, text=titre) l.pack(pady=10,padx=10) top.bind("",self.ok) - self.e = ttk.Entry(top,width=30) + self.e = ttk.Entry(top,width=60) self.e.pack() self.e.focus_set() - b = ttk.Button(top, text="OK", command=self.ok) + b = ttk.Button(top, text=_("OK"), command=self.ok) b.pack(pady=5) - c = ttk.Button(top, text="Annuler", command=self.ko) + c = ttk.Button(top, text=_("Annuler"), command=self.ko) c.pack(pady=5) if basDePage!="none": d = ttk.Label(top, text=basDePage) @@ -4974,7 +9301,152 @@ def ok(self,event='none'): def ko(self): self.top.destroy() return - + +################################## Classe : Dialogue modale : demande un texte #########################" + +class MyDialogTexte: + + def __init__(self,parent,titre=_("Console"),basDePage='none',boutonDialogueTexteOk='OK'): + self.saisie=str() + top = self.top = tkinter.Toplevel(parent,width=250,relief='sunken') + top.transient(parent) + top.geometry("600x400+100+100") + fenetreIcone(self.top) + l=ttk.Label(top, text=titre) + l.pack(pady=10,padx=10) + #top.bind("",self.ok) + # la fenetre pour afficher les textes (traces et aides) + + self.resul200 = ttk.Frame(top,height=100,relief='sunken') # fenêtre texte pour afficher le bilan + self.scrollbar = ttk.Scrollbar(self.resul200) + self.scrollbar.pack(side='right',fill='y',expand=1) + self.scrollbar.config(command=self.yviewTexte) + self.texte201 = tkinter.Text(self.resul200,width=60,height=5,yscrollcommand = self.scrollbar.set,wrap='word') + self.resul200.pack() + self.texte201.pack() + self.texte201.focus_set() + b = ttk.Button(top, text=_(boutonDialogueTexteOk), command=self.ok) + b.pack(pady=5) + c = ttk.Button(top, text=_("Abandon"), command=self.ko) + c.pack(pady=5) + if basDePage!="none": + d = ttk.Label(top, text=basDePage) + d.pack(pady=5) + top.grab_set() + fenetre.wait_window(top) + + def ok(self,event='none'): + self.saisie=self.texte201.get("0.0",'end') + self.top.destroy() + return + + + def ko(self): + self.top.destroy() + return + + def yviewTexte(self, *args): + if args[0] == 'scroll': + self.texte201.yview_scroll(args[1],args[2]) + elif args[0] == 'moveto': + self.texte201.yview_moveto(args[1]) + +################################## Classe : Dialogue minimum modal : choix dans une liste ###########################" + +class choisirDansUneListe: # mode="single" ou 'extended' + + def __init__(self,fenetreParent,listeDeChoix,titre,mode='extended',boutonOk="supprimer"): + if len(listeDeChoix)==0: + return + self.lesChoix = listeDeChoix + self.topChoix = tkinter.Toplevel(fenetreParent) # boite de dialogue + self.topChoix.transient(fenetreParent) + self.topChoix.title(titre) + self.topChoix.geometry("400x250+100+100") + fenetreIcone(self.topChoix) + f = self.topChoix # ttk.Frame(self.topChoix) + frameSelectRep = ttk.Frame(self.topChoix) + invite = ttk.Label(self.topChoix,text=("Choisir :")) + invite.pack(pady=10,padx=10,ipadx=5,ipady=5) + scrollbarV = ttk.Scrollbar(frameSelectRep, orient=('vertical')) + scrollbarH = ttk.Scrollbar(frameSelectRep, orient=('horizontal')) + self.selection = tkinter.Listbox(frameSelectRep, + selectmode=mode, + xscrollcommand=scrollbarH.set, + yscrollcommand=scrollbarV.set, + height= min(10,len(listeDeChoix)), + width= min(70,min(300,(5+max(len (r) for r in listeDeChoix))))) + + self.selection.select_set(1) + listeDeChoix.sort() + for i in listeDeChoix: + self.selection.insert('end',i) + if len(listeDeChoix)>10: + scrollbarV.config(command=self.yview) + scrollbarV.pack(side='right', fill='y') +## scrollbarH.config(command=self.xview) +## scrollbarH.pack(side='bottom', fill='y') + self.selection.pack(side='left', fill='both', expand=1) + frameSelectRep.pack() + self.selection.select_set(0) + b = ttk.Button(f,text=(boutonOk),command=self.valid) + b.pack(pady=5) + c = ttk.Button(f,text=("Annuler"),command=self.cancel) + c.pack(pady=5) + self.topChoix.grab_set() + fenetre.wait_window(self.topChoix) + + def yview(self, *args): + if args[0] == 'scroll': + self.selection.yview_scroll(args[1],args[2]) + elif args[0] == 'moveto': + self.selection.yview_moveto(args[1]) + + def xview(self, *args): + if args[0] == 'scroll': + self.selection.xview_scroll(args[1],args[2]) + elif args[0] == 'moveto': + self.selection.xview_moveto(args[1]) + + def valid(self): + selectionEnCours = self.selection.curselection() + self.topChoix.destroy() + self.selectionFinale = [self.lesChoix[e] for e in selectionEnCours] + + + def cancel(self): + self.topChoix.destroy() + self.selectionFinale = list() + + + +################################## Classe : Dialogue minimum modal : deux boutons OK KO ###########################" + + +def MyDialog_OK_KO(parent=None,titre=_("Question"),b1="OK",b2="KO"): + top = tkinter.Toplevel(parent,width=200,relief='sunken') + top.transient(parent) + top.geometry("400x250+100+100") + fenetreIcone(top) + l=ttk.Label(top, text=titre) + l.pack(pady=10,padx=10) + b = ttk.Button(top, text=b1, command=ok) + b.pack(pady=5) + c = ttk.Button(top, text=b2, command=ko) + c.pack(pady=5) + top.grab_set() + parent.wait_window(top) + parent.mainloop() + +def ok(event='none'): + print("OK") + try: f.destroy() + except: pass + return 1 + +def ko(event=None): + print("KO") + return 0 ################################## Style pur TTK ###########################" @@ -4982,15 +9454,8 @@ def monStyle(): pass ttk.Style().configure("TButton", padding=6, relief="flat",background="#ccc") - -################################## LANCEMENT DU PROGRAMME ########################################################### - -# si on ouvre ce script comme programme principal alors on instancie un objet de la classe Interface sur la fenêtre principale de l'outil : +################################### boucle sur l'interface tant que continuer est vrai : -continuer = True -messageDepart = str() -compteur = 0 -iconeTexte = "R0lGODlhIAAgAIcAMQQCBJSGJNTSPHQKBMTCpGxKBPziXJxmJIR6BOTCXPTybDwCBHR2TMTGhPTmjOzmpJxuBMy+pIRyLDweDPz+1MTGjOzuhDwmBMRaFPz+pHx6LKRiLPzibDQiDMzKZIxqTKR6NOy2fHxCBNTCdEwaBISGTPzqfBwCBPTmpJRuLMzCjKxqBPTmnKxuBOzqnNzGXJQ2BHxGBIx2FIR+fMzGfOTmtMS+vIRyPPz67PTubBQCBJyGJMTCtPzqVKRmHPzSfFQWBIRuTJxuFEQeBPz+vHx2RKxiLNTKXMzCnPzqZAQKBHROBHx6JPz+hPzihPTqfEwqLJxqLJR+XOS+bEwiBMzGhPzenAwCBIyKNNzKTMzCpHxyTOzqpIxyLEwqBJxmRMzKbKx6PIQ+BNTGdISCXMzGjIxCBNS6vPz+/PzqXKRqHPzeZGQOBPzqdPzmjMzOVGwSBMTGpGxGHIR6FPTyfKRuDMy+tDwiBPz+5MTGnEQqBPz+tIR2NKRmLDQiJMzOXJx6VEwWDIx6fPyubLR6FCwCBHRCHIx+BMy6vOS+hPzedPzilIxuPIR2PJSGNJR2hFQaBJRqPKxmFJyCNFwSBIR2JPTqjJQ+BPTqlOzmtKRuFNTOTHRKBIyGTCQCBNzGbJw2BIRGBPz+zPz+lFQiBHxyXMy6zPzmVMzKdPz+7PzuTEQiBHx6PPzuZPzmfKRyBAQGBHQOBJxqJMTKhDwqBKR+NEweBMzGnHRSBPTufMzKhAwGBIRCBPzuXIR+FPzmlFwWBMTCrPTydHR2VOzmrMy+rIRyNPz+3MTGlOzujPz+rHx6NDQiFIxqVNTCfPzqhPTmrMzClIRyRPTudMTCvKRmJIRuVJxuHEQeDPz+xNTKZOS+dIyKPOzqrIxyNNTGfISCZMzGlKRqJDwiDKRmNMzOZPzefPTqnOzmvMzKfPz+9PzubPzmhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIAAgAAcI/gABCBxIsKDBgwgTKlxI8MoVHVcYShT4cMIdHRAnKtRxwZIlGsa+eIqo0eAVCey0/fHATgSkEyRLUrwCjUg6MH9yHXECZKRMih0IVKjAZY+FUexCGAryU+AWPHiQVchTJsO0F26waNAASyaDVKkodCOAzMERDxb2uEiGJaZEcOrUUdDF5du2KZiq5EEGxsEQHROvlEqFRxSLADIKWPmGLFgeD09A2HKbUAc2JGUSxYDAScYYLqJE6bKwKY2XVRgpFzwxpNOiKNXqOBnTrUI4ZN2U5VCVZlKQOw5VUzTmwtEGYIyiEQDLgwcBLsqyCKNBjIsEWycQwlpGowslSoC0/qAZj0bdsVmoLCjTJSrbNyurhAOYlc0YpQWRpJwxVf5YmWQeoNIAHuqkcgw0KnBlECzdNNAFEJTY8gEUjyASgSi/vJCLI9DcslwceFSByS4HlZBMALL0pMMEzQTyxQa8qAFBFJM4kE4Nxxg4Ai0HLfNHG6SoYYsnhRQJBDBGqBGDDyI4sQMYZYCFQheUwaKBAr28UkcoK8DAhidgDmGLLCJIMogZTqCCRyploJARQRq8ccgSBpyyBgYDBIKRDid0YQ4hMEjyggsE8IBMFQ5cENMVdyCgwCZJNLEGKHlC9NAdbfTSQxJPVNAcMlx4kChgADjEhAe5ePCHKz/EUkhGfRjJIIAA08wSBw/mqeDCHtKQKtAuLrRHxCeKmLGBJ3ueoEcbROTIw3jF4ACVarAMEwc6RCRgDghyTKDDRU44k0p56lBjwyN+SFQEH3w4wkKbc1gSjXjqFGNNKSXBou8uy5TQgHrH8EDNDOPIpxEDeeSRCThNLaRvwxBHLFFAADs=" if __name__ == "__main__": while continuer: compteur += 1 @@ -4999,6 +9464,8 @@ def monStyle(): if messageDepart==str(): interface.afficheEtat() else: - interface.encadre(messageDepart) # affiche les infos restaurées : - fenetre.mainloop() # boucle tant que l'interface existe + interface.encadre(str(messageDepart)) # affiche les infos restaurées : + try: fenetre.mainloop() # boucle tant que l'interface existe + except: pass + diff --git a/InterfaceCEREMA/Documentation_AperoDeDenis.pdf b/InterfaceCEREMA/Documentation_AperoDeDenis.pdf new file mode 100644 index 0000000..a2a3051 Binary files /dev/null and b/InterfaceCEREMA/Documentation_AperoDeDenis.pdf differ diff --git a/InterfaceCEREMA/Interface graphique MicMac - instalaltion et prise en main.pdf b/InterfaceCEREMA/Interface graphique MicMac - instalaltion et prise en main.pdf deleted file mode 100644 index d4325a3..0000000 Binary files a/InterfaceCEREMA/Interface graphique MicMac - instalaltion et prise en main.pdf and /dev/null differ diff --git a/InterfaceCEREMA/aperodedenis_3.14-2_amd64.deb b/InterfaceCEREMA/aperodedenis_3.14-2_amd64.deb new file mode 100644 index 0000000..3829674 Binary files /dev/null and b/InterfaceCEREMA/aperodedenis_3.14-2_amd64.deb differ diff --git a/InterfaceCEREMA/historique_des_versions.txt b/InterfaceCEREMA/historique_des_versions.txt new file mode 100644 index 0000000..4b35391 --- /dev/null +++ b/InterfaceCEREMA/historique_des_versions.txt @@ -0,0 +1,251 @@ +Historique des principales versions de l'interface CEREMA AperoDeDenis + + Version 1.5 : première version diffusée sur le site de l'IGN le 23/11/2015. + + Version 1.55 : décembre 2015 + Sous Windows le fichier paramètre est placé sous le répertoire APPDATA de l'utilisateur, + ce qui règle les questions relatives aux droits d'accès en écriture. + + Version 1.60 : + - Ajout des fonctions : + - Qualité des photos lors du dernier traitement + - Exportation du chantier en cours + - Importation d'un chantier (permet de recopier le chantier sur un autre répertoire, disque, ordinateur, système) + - Ajout d'un item du menu édition fusionnant les images 3D. + - Plusieurs images maîtresses, plusieurs masques. + - Choix possible de fichiers PNG, BMP, GIF, TIF. Ces fihiers sont convertit en JPG. + - Ajout d'un item du menu Outils permettant de modifier les exifs. + - Les fichiers 'trace' sont enregistrés au format utf-8. + + Version 2 : + - Choix de photos pour la calibration intrinsèque par Tapas + - Possibilité de relancer Malt sans relancer Tapioca/Tapas tout en conservant les images 3D générées. + - Modification possible des options par défaut dans le menu outils : + - les options du chantier en cours deviennent les options par défaut. + - Conservation de tous les fichiers modele3D.ply pour un même chantier. + - Choix du niveau de zoom d'arrêt de la procédure Malt : de 1 à 8. + - Création de tous les fichiers .ply correspondants à tous les niveaux de zoom calculés. + - Ajout d'un item du menu édition listant et visualisant toutes les images 3D générées. + - Choix du nombre de photos à retenir autour de l'image maître pour Malt. + - Traitement des vidéos (par exemple GoPro) : décompactage, sélection, mise à jour de l'exif. + - Ajout de deux contrôles sur le lot des photos : mêmes dimensions, même focale. + - Ajout d'un item 'historique' dans le menu Aide. + + Version 2.10 : février 2016 + - Ajout d'un item du menu édition fusionnant les images 3D. + - Plusieurs images maîtresses, plusieurs masques pour Malt. + - Choix possible de fichiers PNG, BMP, GIF, TIF. + - Ajout d'un item du menu Outils permettant de modifier les exifs. + + Version 2.20 : Février 2016 + - Maintien des options compatibles lors du choix de nouvelles photos. + + Version 2.30 : Mai 2016 + - Modification des options par défaut (menu outils). + - Référentiel GPS calculé après Tapas. + - La virgule devient un séparateur décimal accepté. + - Possiblité d'appliquer la calibration GPS sans relancer malt. + + Version 2.40 : Mai 2016 + - Ajout de l'option (Statue ou QuickMac) pour C3DC. + + Version 2.45 : Mai 2016 + - Référentiel GPS calculé après Tapas (et toujours avant Malt). + - La virgule est un séparateur décimal accepté.\n"+\ + + Version 2.5 : Juin 2016 + - Ajout de Tawny aprés Malt en mode Ortho + + Version 2.50 : Juin 2016 + - Item dans le menu paramètrage pour désactiver le message de lancement. + + Version 2.60 : juillet 2016 + - saisie des incertitudes sur la position des points gps + + Version 2.61 + - correction d'un bogue de compatibilité ascendante sur les points GPS + + Version 3.00 : novembre 2016 + - version bilingue : ajout de la langue anglaise, par Alexandre Courallet + La langue est demandée au premier lancement. + Un item du menu "paramètrage" ("Settings") permet de changer la langue utilisée. + + Version 3.10 : novembre 2016 + - Ajout d'un item permettant de sélectionner les meilleures photos suivant les points homologues + (compléte et différe du choix des meilleures images vidéos) + + Version 3.13 décembre 2016 + - la distance de la calibration accepte une unité + - lancement de Tapas accéléré + - diverses corrections de bogues + + Version 3.14 30 décembre 2016 + - correction d'une régression au démarrage + + Version 3.20 : 17 janvier 2017 + - Les photos autour de la maitresse pour Malt ne sont plus "autour" mais choisies parmi les meilleures en correspondances + - Ajout d'un choix pour Malt : AperoDeDenis, l'interface recherche les maitresses et les photos correspondantes + - Ajout filtre pour afficher l'erreur max sur gcpbascule (erreur positionnement des points GPS. + - controle affiné des points gps : + on indique ceux qui ne sont placés sur une seule photo et on vérifie la présence de 3 points sur 2 photos + - Aprés plantage durant malt ou fusion : on renomme les JPG et les PLY lors du rédémarrage (reste pb semblable pour calibration intrinsèque) + - Suppression d'un point GPS sur une photo (avant : suppression de tous les points) + - Affichage dans l'état du chantier des points GPS positionnés sur une seule photo + - Non mise dans le xml des points gps positionnés une seule fois. + - Si le controle des points GPS est négatif alors les fichiers xml ne sont pas créés + + Version 3.30 :26 janvier 2017 + - Nouveauté : faire un masque sur une mosaique Tarama pour le mode Ortho de Malt et draper le résultat avec une orthomosaïque tawny. + - Possibilité de créer une mosaique aprés tapas sur toutes les photos par "Tarama" + - Saisir un masque sur la mosaïque créée : par l'outil de saisie de masque + - Lancer Malt option Ortho : attention les photos doivent concerner un terrain naturel tel que z=f(x,y) (un seul z pour tout (x,y) + - Lancer Tawny pour créer une ortho-mosaïque sur le résultat de malt, pour draper le nuage densifié + - Le masque Malt peut être inversé : la sélection concerne l'extérieur du polygone au lieu de l'intérieur. + - menu edition : affichage des mosaïques Tarama et Tawny + - Un item de menu "expert" permettant de saisir et d'exécuter des commandes en mode "console" + + Version 3.32 : 7 février 2017 + - Possibilité de copier des points gps d'un chantier à un autre (menu expert) + + Version 4.0 : 4 avril 2017 + + - Ajout d'un item de menu : Indices_surfaciques proposant 3 fonctions (Réalisation : Dhia Eddine Stambouli) + - Calcul d'un maillage régulier à partir d'un modéle 3D représentant une surface calibrée ou géoréférencée. + Ce maillage est affiché, la tortuosité et la rugosité sont calculées. + - La profondeur moyenne de profil ainsi que la profondeur moyenne de texture équivalente sont calculées. + Les profils sont affichés sur la surface ou figurés par une courbe. + - Le pas du maillage est déterminé par l'utilisateur, dans l'unité du modéle 3D. + - Deux méthodes sont proposées pour le calcul de l'interpolation + + Version 4.10 : octobre 2017 + + - Affichage de la taille disque du chantier, en MO, dans l'état du chantier. + - La fonction "Du ménage" propose un choix : nettoyer le chantier ou le supprimer totalement + - Nouvelle icone pour la fenêtre : logo du cerema. + - Correction de 2 bugs concernant : + - la fonction "renommer un chantier" + - Un message parfois non pertinent sur l'absence de focales + + Version 4.11 : Noël 2017 + - Diffusion de la version 4.10 sur GitHub + + Version 5.0 : janvier 2018 + - Suppression de l'item "Indices surfaciques" de la version 4.0 + +----------------------------------------------------------------------- +History of the main versions of the CEREMA AperoDeDenis interface + + Version 1.5: first version diffused on the site of the IGN the 23/11/2015. + + Version 1.55: December 2015 + Under Windows the parameter file is placed under the APPDATA directory of the user, + Which resolves issues related to write access rights. + + Version 1.60: + - Added functions: + - Quality of photos during the last treatment + - Export of the site in progress + - Import a site (allows to copy the site on another directory, disk, computer, system) + - Added a menu item editing the 3D images. + - Several master images, several masks. + - Possible selection of PNG, BMP, GIF, TIF files. These files are converted to JPG. + - Added an item in the Tools menu to modify exifs. + - 'trace' files are saved in utf-8 format. + + Version 2: + - Choice of photos for intrinsic calibration by Tapas + - Possibility to restart Malt without restarting Tapioca / Tapas while retaining the 3D images generated. + - Possible modification of the default options in the tool menu: + - the current job options become the default options. + - Preservation of all files model3D.ply for the same site. + - Choice of the stop zoom level of the Malt procedure: from 1 to 8. + - Create all corresponding .ply files at all calculated zoom levels. + - Added an item from the edit menu listing and viewing all generated 3D images. + - Choice of the number of photos to remember around the master image for Malt. + - Processing of videos (for example GoPro): unpacking, selection, update of exif. + - Added two controls on the batch of photos: same dimensions, even focal length. + - Added a 'history' item in the Help menu. + + Version 2.10: February 2016 + - Added a menu item editing the 3D images. + - Several master images, several masks for Malt. + - Possible selection of PNG, BMP, GIF, TIF files. + - Added an item in the Tools menu to modify exifs. + + Version 2.20: February 2016 + - Maintain compatible options when choosing new photos. + + Version 2.30: May 2016 + - Changing the default options (tool menu). + - GPS baseline calculated after Tapas. + - The comma becomes an accepted decimal separator. + - Possibility to apply GPS calibration without restarting malt. + + Version 2.40: May 2016 + - Added option (Statue or QuickMac) for C3DC. + + Version 2.45: May 2016 + - GPS baseline calculated after Tapas (and always before Malt). + - The comma is an accepted decimal separator. \ N "+ \ + + Version 2.5: June 2016 + - Added Tawny after Malt in Ortho mode + + Version 2.50: June 2016 + - Item in the setup menu to disable the launch message. + + Version 2.60: July 2016 + - entering uncertainties on the position of gps points + + Version 2.61 + - Fixed an upward compatibility bug on GPS points + + Version 3.00: November 2016 + - bilingual version: addition of the English language, by Alexandre Courallet + Language is requested at first launch. + An item in the "Settings" menu allows you to change the language used. + + Version 3.10: November 2016 + - Added an item to select the best photos following the homologous points + (Complete and different from the choice of the best video images) + + Version 3.13 December 2016 + - the calibration distance accepts one unit + - launch of Tapas acceleré + - various bug fixes + + Version 3.14 30 December 2016 + - correction of a regression at start-up + + Version 3.30: 26 January 2017 + New: make a mask on a Tarama mosaic for the Malt Ortho mode and drape the result with a tawny orthomosaic. + 1) Possibility of creating a mosaic after tapas on all the photos by "Tarama" + 2) enter a mask on the mosaic created: by the mask input tool + 3) Launch Malt option Ortho: be careful the photos must relate to a natural terrain such as z = f (x, y) (a single z for all (x, y) + 4) Launch Tawny to create an ortho-mosaic on the malt result, to drape the densified cloud + The Malt mask can be inverted: the selection concerns the outside of the polygon instead of the inside. + Menu edition: displaying Tarama and Tawny mosaics + An "expert" menu item for entering and executing commands in "console" mode + + Version 3.32 : 7 february 2017 + - Ability to copy gps points from one project to another (expert menu) + + Version 4.0 : 4 avril 2017 + + Add menu item : Indices_surfaciques. + + Calcul d'un maillage régulier à partir d'un modéle 3D représentant une surface calibrée ou géoréférencée. + Ce maillage est affiché, la tortuosité et la rugosité sont calculées. + La profondeur moyenne de profil ainsi que la profondeur moyenne de texture équivalente est calculée. + les profils sont affichés sur la surface ou exposés en détails. + Le pas du maillage est exprimé dans l'unité du modéle. + + Version 4.10 octobre 2017 + + Affichage de la taille du chantier en MO dans l'état du chantier. + La fonction "Du ménage" propose un choix : nettoyer le chantier ou le supprimer totalement + Nouvelle icone pour la fenêtre : logo du cerema. + Correction de 2 bugs : renommer et message parfois non pertinent sur l'absence de focales. + + Version 4.11 Noël 2017 + \ No newline at end of file diff --git a/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.mo b/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.mo new file mode 100644 index 0000000..74947c9 Binary files /dev/null and b/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.mo differ diff --git a/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.po b/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.po new file mode 100644 index 0000000..c73c058 --- /dev/null +++ b/InterfaceCEREMA/locale/en/LC_MESSAGES/AperoDeDenis.po @@ -0,0 +1,6753 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2017-02-07 13:43+0100\n" +"PO-Revision-Date: 2017-02-07 13:44+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 1.8.11\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: aperodedenis.py:272 +msgid " lancement d'aperodedenis" +msgstr " Launching AperoDeDenis" + +#: aperodedenis.py:289 aperodedenis.py:2659 aperodedenis.py:3335 +#: aperodedenis.py:3356 aperodedenis.py:3376 aperodedenis.py:3397 +#: aperodedenis.py:3482 aperodedenis.py:7882 +msgid "Tous" +msgstr "All" + +#: aperodedenis.py:290 +msgid "Ply à lire" +msgstr "Ply to read" + +#: aperodedenis.py:293 +msgid "Fichier à lire : " +msgstr "File to read: " + +#: aperodedenis.py:299 +msgid "Il ne s'agit pas d'un fichier ply issu de MicMac !" +msgstr "This ply file is not from MicMac !" + +#: aperodedenis.py:302 +msgid "Fichier à écrire : " +msgstr "File to write:" + +#: aperodedenis.py:314 +msgid "nombre de points : " +msgstr "Number of points: " + +#: aperodedenis.py:325 +msgid " le format attendu est : fffBBB" +msgstr "The awaited format is: fffBBB" + +#: aperodedenis.py:325 +msgid "" +"Le format des données indique qu'il ne s'agit pas d'un ply généré par " +"MicMac. Le format trouvé est : " +msgstr "" +"The format of the datas shows that it's not a ply generated from MicMac. The " +"found format is: " + +#: aperodedenis.py:328 +msgid "Longueur du fichier : " +msgstr "File length: " + +#: aperodedenis.py:329 +msgid "format du fichier > = big_endian, < = little_endian :" +msgstr "File format > = big_endian, < = little_endian:" + +#: aperodedenis.py:330 +msgid " longueur : " +msgstr " length: " + +#: aperodedenis.py:330 +msgid "Format des données : " +msgstr "Data format: " + +#: aperodedenis.py:332 +msgid "patience : écriture du fichier xyz en cours" +msgstr "Please wait: writing xyz file..." + +#: aperodedenis.py:337 +msgid " fin = " +msgstr " end = " + +#: aperodedenis.py:337 +msgid " longueur = " +msgstr " length = " + +#: aperodedenis.py:337 +msgid "Plage des données : début = " +msgstr "Data range: beginning= " + +#: aperodedenis.py:341 +msgid "" +"Erreur lors du décodage des données, le ply ne provient pas de micmac. " +"Erreur : " +msgstr "" +"Error when decoding datas : the ply file was not provided from MicMac. " +"Error : " + +#: aperodedenis.py:356 aperodedenis.py:425 +msgid "nom du fichier contenant les données : à déterminer" +msgstr "Name of the file containing the datas: to be determined." + +#: aperodedenis.py:405 +msgid " pas du maillaige : " +msgstr " mesh range: " + +#: aperodedenis.py:548 +msgid "profil n°" +msgstr "profile n°" + +#: aperodedenis.py:560 +msgid "Tracer le masque" +msgstr "Draw the mask" + +#: aperodedenis.py:562 +msgid "Saisie sur la photo : " +msgstr "Drawing on picture:" + +#: aperodedenis.py:611 +msgid "Inverser" +msgstr "Reverse" + +#: aperodedenis.py:612 aperodedenis.py:924 +msgid "Valider" +msgstr "Confirm" + +#: aperodedenis.py:613 aperodedenis.py:927 aperodedenis.py:3470 +#: aperodedenis.py:5091 aperodedenis.py:5117 aperodedenis.py:5128 +#: aperodedenis.py:5139 aperodedenis.py:5155 aperodedenis.py:5176 +#: aperodedenis.py:6263 aperodedenis.py:8250 aperodedenis.py:9224 +msgid "Abandon" +msgstr "Abort" + +#: aperodedenis.py:616 +msgid "molette de la souris = zoom," +msgstr "scroll button = zoom" + +#: aperodedenis.py:617 +msgid "utilisable avant ET pendant le tracé" +msgstr "usable before AND during drawing" + +#: aperodedenis.py:618 +msgid "glisser-déposer actif avant le tracé=" +msgstr "active slip-drop before the drawing =" + +#: aperodedenis.py:619 +msgid "Tracer :" +msgstr "Draw:" + +#: aperodedenis.py:620 +msgid "" +"Clic gauche : ajouter un point;\n" +" double clic gauche : fermer le polygone," +msgstr "Left click: add a point; double left clic: close the polygon," + +#: aperodedenis.py:621 +msgid "Touche Del pour supprimer un point ou le polygone," +msgstr "Use Del to delete a point or the polygon," + +#: aperodedenis.py:698 +msgid "Il faut au moins 2 points dans le polygone." +msgstr "There must be at least 2 points in the polygon" + +#: aperodedenis.py:728 aperodedenis.py:1016 +msgid "Zoom maximum atteint" +msgstr "Maximum zoom reached" + +#: aperodedenis.py:814 +msgid "Erreur suppression d'info bulle : " +msgstr "Tooltip deleting error:" + +#: aperodedenis.py:876 +msgid "Calibration GPS " +msgstr "GPS calibration" + +#: aperodedenis.py:877 +msgid "Position des points sur la photo : " +msgstr "Position of the points on the picture:" + +#: aperodedenis.py:926 +msgid "Supprimer un ou plusieurs points" +msgstr "Delete one or more points" + +#: aperodedenis.py:934 +msgid "Changer la couleur des libellés" +msgstr "Change the color of the text." + +#: aperodedenis.py:941 +msgid "Utiliser la molette pour zoomer/dezoomer pendant la saisie." +msgstr "Use the scroll button to zoom/unzoom when drawing" + +#: aperodedenis.py:958 +msgid "Placer le point " +msgstr "Place the point" + +#: aperodedenis.py:961 +msgid "Point " +msgstr "Point" + +#: aperodedenis.py:1169 aperodedenis.py:1170 +msgid " : une interface graphique pour MicMac..." +msgstr ": a Graphical User Interface for MicMac..." + +#: aperodedenis.py:1174 +msgid "Fermeture inatendue de la fenêtre." +msgstr "Unexpected closure of the window" + +#: aperodedenis.py:1177 +msgid "Erreur initialisation de la fenêtre principale : " +msgstr "Error initialising the main window:" + +#: aperodedenis.py:1197 aperodedenis.py:6232 +msgid "Nouveau chantier" +msgstr "New project" + +#: aperodedenis.py:1198 +msgid "Ouvrir un chantier" +msgstr "Open project" + +#: aperodedenis.py:1200 +msgid "Enregistrer le chantier en cours" +msgstr "Save current project" + +#: aperodedenis.py:1201 +msgid "Renommer ou déplacer le chantier en cours" +msgstr "Rename or move current project" + +#: aperodedenis.py:1203 +msgid "Exporter le chantier en cours" +msgstr "Export current project" + +#: aperodedenis.py:1204 +msgid "Importer un chantier" +msgstr "Import project" + +#: aperodedenis.py:1206 +msgid "Du ménage !" +msgstr "Let's clean!" + +#: aperodedenis.py:1208 +msgid "Quitter" +msgstr "Exit" + +#: aperodedenis.py:1213 +msgid "Afficher l'état du chantier" +msgstr "Display project progress" + +#: aperodedenis.py:1215 +msgid "Visualiser toutes les photos sélectionnées" +msgstr "Diplay all selected pictures" + +#: aperodedenis.py:1216 +msgid "Visualiser les points GPS" +msgstr "Display GPS points" + +#: aperodedenis.py:1217 +msgid "Visualiser les maîtresses et les masques" +msgstr "Display master pictures and masks" + +#: aperodedenis.py:1218 +msgid "Visualiser le masque sur mosaique Tarama" +msgstr "View the mask on mosaic Tarama" + +#: aperodedenis.py:1219 +msgid "Visualiser le masque 3D" +msgstr "Display 3D mask" + +#: aperodedenis.py:1220 +msgid "Visualiser la ligne horizontale/verticale" +msgstr "Display horizontal/vertical line" + +#: aperodedenis.py:1221 +msgid "Visualiser la zone plane" +msgstr "Display plane area" + +#: aperodedenis.py:1222 +msgid "Visualiser la distance" +msgstr "Display distance" + +#: aperodedenis.py:1223 +msgid "Visualiser les photos pour la calibration intrinsèque" +msgstr "Display pictures for intrinsic calibration" + +#: aperodedenis.py:1225 +msgid "Afficher la trace complète du chantier" +msgstr "Display the complete project log" + +#: aperodedenis.py:1226 +msgid "Afficher la trace synthétique du chantier" +msgstr "Display the synthetic project log" + +#: aperodedenis.py:1228 +msgid "Afficher la mosaïque Tarama" +msgstr "Display mosaic Tarama" + +#: aperodedenis.py:1229 +msgid "Afficher l'ortho mosaïque Tawny" +msgstr "Display ortho mosaic Tawny" + +#: aperodedenis.py:1231 +msgid "Afficher l'image 3D non densifiée" +msgstr "Display undensified 3D picture" + +#: aperodedenis.py:1232 +msgid "Afficher l'image 3D densifiée" +msgstr "Display densified 3D picture" + +#: aperodedenis.py:1234 +msgid "Lister-Visualiser les images 3D" +msgstr "List-Display 3D pictures" + +#: aperodedenis.py:1235 +msgid "Fusionner des images 3D" +msgstr "Merge 3D pictures" + +#: aperodedenis.py:1242 aperodedenis.py:3480 +msgid "Choisir des photos" +msgstr "Select pictures" + +#: aperodedenis.py:1243 +msgid "Options" +msgstr "Options" + +#: aperodedenis.py:1245 +msgid "Lancer MicMac" +msgstr "Launch MicMac" + +#: aperodedenis.py:1250 +msgid "Options (GoPro par défaut)" +msgstr "Options (Default GoPro)" + +#: aperodedenis.py:1252 +msgid "Nouveau chantier : choisir une vidéo GoPro, ou autre" +msgstr "New project : choose a GoPro video, or else" + +#: aperodedenis.py:1253 +msgid "Sélection des meilleures images" +msgstr "Select the best pictures" + +#: aperodedenis.py:1259 +msgid "Nom et focale de l'appareil photo" +msgstr "Name and focal length of the camera" + +#: aperodedenis.py:1260 +msgid "Toutes les focales des photos" +msgstr "All focal length of pictures" + +#: aperodedenis.py:1261 +msgid "Mettre à jour DicoCamera.xml" +msgstr "Update DicoCamera.xml" + +#: aperodedenis.py:1263 +msgid "Qualité des photos du dernier traitement" +msgstr "Quality of the pictures of last process" + +#: aperodedenis.py:1264 +msgid "Sélectionner les N meilleures photos" +msgstr "Select the N best pictures" + +#: aperodedenis.py:1266 +msgid "Qualité des photos 'line'" +msgstr "Quality of 'line' pictures" + +#: aperodedenis.py:1267 +msgid "Qualité des photos 'All' " +msgstr "Quality of 'All' pictures." + +#: aperodedenis.py:1269 +msgid "Modifier l'exif des photos" +msgstr "Edit exif of pictures" + +#: aperodedenis.py:1271 aperodedenis.py:8855 aperodedenis.py:8873 +msgid "Modifier les options par défaut" +msgstr "Change default options" + +#: aperodedenis.py:1276 +msgid "Exécuter lignes de commande" +msgstr "Execute command lines" + +#: aperodedenis.py:1277 +msgid "Ajouter les points GPS d'un chantier" +msgstr "Add GPS points from an other project" + +#: aperodedenis.py:1283 +msgid "Désactiver le 'tacky' message de lancement" +msgstr "Desactivate the launching 'tacky' message." + +#: aperodedenis.py:1285 +msgid "Activer le 'tacky' message de lancement" +msgstr "Activate the launching 'tacky' message." + +#: aperodedenis.py:1288 +msgid "Afficher les paramètres" +msgstr "Display settings" + +#: aperodedenis.py:1290 +msgid "Associer le répertoire bin de MicMac" +msgstr "Link the MicMac\\bin directory" + +#: aperodedenis.py:1291 +msgid "Associer 'exiftool'" +msgstr "Link the 'exiftool' directory" + +#: aperodedenis.py:1292 +msgid "Associer 'convert' d'ImageMagick" +msgstr "Link the ImageMagick's 'convert' directory" + +#: aperodedenis.py:1293 +msgid "Associer 'ffmpeg (décompacte les vidéos)" +msgstr "Link the 'ffmpeg' (unpacks videos) directory" + +#: aperodedenis.py:1294 +msgid "Associer 'Meshlab' ou 'CloudCompare'" +msgstr "Link the 'Meshlab' or 'CloudCompare' directory" + +#: aperodedenis.py:1296 +msgid "Changer la langue" +msgstr "Change language" + +#: aperodedenis.py:1298 +msgid "Désactive/Active le tacky message de lancement..." +msgstr "Desactivate/Activate launching 'tacky' message..." + +#: aperodedenis.py:1303 +msgid "Affichage de la surface interpolée" +msgstr "Display the interpolated area" + +#: aperodedenis.py:1304 +msgid "Calcul des indices" +msgstr "Parameters calculation" + +#: aperodedenis.py:1305 +msgid "Calcul de la PMP" +msgstr "PMP calculation" + +#: aperodedenis.py:1310 +msgid "Pour commencer..." +msgstr "Get started" + +#: aperodedenis.py:1311 aperodedenis.py:1326 +msgid "Aide" +msgstr "Help" + +#: aperodedenis.py:1312 +msgid "Quelques conseils" +msgstr "Advices" + +#: aperodedenis.py:1313 +msgid "Historique" +msgstr "Changelog" + +#: aperodedenis.py:1314 +msgid "A Propos" +msgstr "About" + +#: aperodedenis.py:1318 +msgid "Fichier" +msgstr "File" + +#: aperodedenis.py:1319 +msgid "Edition" +msgstr "Edit" + +#: aperodedenis.py:1321 +msgid "Vidéo" +msgstr "Video" + +#: aperodedenis.py:1322 +msgid "Outils" +msgstr "Tools" + +#: aperodedenis.py:1323 +msgid "Expert" +msgstr "Expert" + +#: aperodedenis.py:1324 +msgid "Paramétrage" +msgstr "Settings" + +#: aperodedenis.py:1359 +msgid "Pas de répertoire désigné pour MicMac\\bin" +msgstr " No designated directory for MicMac\\bin" + +#: aperodedenis.py:1360 +msgid "Pas de fichier désigné pour ouvrir les .PLY" +msgstr "No designated programm to open .PLY files." + +#: aperodedenis.py:1361 +msgid "Pas de chemin pour ExifTool" +msgstr "No path for exiftool" + +#: aperodedenis.py:1362 +msgid "Pas de fichier pour mm3d" +msgstr "No file for mm3d" + +#: aperodedenis.py:1363 +msgid "Pas de fichier pour ffmpeg" +msgstr "No file for ffmpeg" + +#: aperodedenis.py:1364 +msgid "Pas de version MicMac" +msgstr "No MicmMac's version" + +#: aperodedenis.py:1366 +msgid "Pas de version Image Magick" +msgstr "No ImageMagick's version" + +#: aperodedenis.py:1494 aperodedenis.py:1514 +msgid "Echelle image (-1 pour l'image entière) :" +msgstr "Picture scale (-1 for the whole picture)" + +#: aperodedenis.py:1502 +msgid "Echelle image réduite : " +msgstr "Reduced scale picture:" + +#: aperodedenis.py:1506 +msgid "Seconde Echelle (-1 pour l'image entière) :" +msgstr "Second scale (-1 for the whole picture)" + +#: aperodedenis.py:1516 +msgid "Delta (nombre d'images se recouvrant, avant et après) : " +msgstr "Delta (number of pictures covering themselves, before and after)" + +#: aperodedenis.py:1544 +msgid "Choisir quelques photos pour la calibration intrinsèques" +msgstr "Choose some pictures for the intrinsic calibration" + +#: aperodedenis.py:1547 +msgid " N'utiliser ces photos que pour la calibration" +msgstr "Use these picture for the calibration only" + +#: aperodedenis.py:1547 +msgid "(exemple : focales différentes)" +msgstr "(example: differents focal lengths)" + +#: aperodedenis.py:1548 +msgid "Toutes ces photos doivent avoir la même focale," +msgstr "All of theses pictures must have the same focal length," + +#: aperodedenis.py:1548 +msgid "éventuellement différente de la focale des autres photos." +msgstr "but can have a different focal length than the other pictures." + +#: aperodedenis.py:1550 +msgid "" +"lancer Tarama après TAPAS : mosaique pouvant définir un masque pour Malt/" +"ortho)" +msgstr "" +"Launch Tarama after TAPAS: make mosaic to define a mask for Malt / ortho" + +#: aperodedenis.py:1553 +msgid "Arrêter le traitement après TAPAS" +msgstr "Stop processing after TAPAS." + +#: aperodedenis.py:1574 aperodedenis.py:1609 +msgid "Choisir entre :" +msgstr "Choose between:" + +#: aperodedenis.py:1577 +msgid "Ligne horizontale" +msgstr "Horizontal line" + +#: aperodedenis.py:1581 aperodedenis.py:1616 +msgid "ou" +msgstr "or" + +#: aperodedenis.py:1584 +msgid "Ligne verticale" +msgstr "Vertical line" + +#: aperodedenis.py:1597 aperodedenis.py:1631 +msgid "ET :" +msgstr "AND:" + +#: aperodedenis.py:1612 +msgid "Zone plane horizontale" +msgstr "Plane horizontal area" + +#: aperodedenis.py:1619 +msgid "Zone plane verticale" +msgstr "Plane vertical area" + +#: aperodedenis.py:1642 +msgid "Distance entre les 2 points :" +msgstr "Distance between the 2 points:" + +#: aperodedenis.py:1647 +msgid "Placer 2 points identiques sur 2 photos" +msgstr "Position of 2 identical points on 2 pictures" + +#: aperodedenis.py:1657 +msgid "Pour annuler la calibration mettre la distance = 0" +msgstr "To abort calibration, set the distance to 0" + +#: aperodedenis.py:1664 +msgid "UrbanMNE pour photos urbaines" +msgstr "UrbanMNE for urban pictures" + +#: aperodedenis.py:1665 +msgid "GeomImage pour photos du sol ou d'objets" +msgstr "GeomImage for pictures of ground or objects " + +#: aperodedenis.py:1666 +msgid "Ortho pour orthophotos de terrain naturel [f(x,y)=z)]" +msgstr "Ortho for orthophotos of natural ground [f (x, y) = z)]" + +#: aperodedenis.py:1667 +msgid "AperoDeDenis choisit pour vous les options de GeomImage" +msgstr "AperoDeDenis chooses for you the options of GeomImage" + +#: aperodedenis.py:1687 aperodedenis.py:4352 +msgid "Choisir les maîtresses" +msgstr "Choose master pictures" + +#: aperodedenis.py:1689 aperodedenis.py:1723 +msgid "Tracer les masques" +msgstr "Draw masks" + +#: aperodedenis.py:1690 +msgid "Pour supprimer un masque : supprimer la maitresse" +msgstr "To delete a mask, delete the master picture." + +#: aperodedenis.py:1690 aperodedenis.py:1724 +msgid "Attention : Le masque 3D de C3DC a la priorité sur Malt" +msgstr "Warning: 3D mask from C3DC has priority over Malt." + +#: aperodedenis.py:1692 +msgid "Nombre de photos à retenir autour de l'image maitresse (-1 = toutes) :" +msgstr "Number of photos to use around the image maitresse (-1 = All):" + +#: aperodedenis.py:1699 +msgid "Zoom final : 8, 4, 2 ou 1 (8=le plus rapide, 1=le plus précis)" +msgstr "Final zoom: 8,4,2 or 1 (8 = fastest, 1 = most accurate)" + +#: aperodedenis.py:1706 +msgid "Lancer tawny après MALT" +msgstr "Launch Tawny after MALT" + +#: aperodedenis.py:1707 +msgid "Tawny génère une ortho mosaïque qui sera drapée sur le nuage densifié." +msgstr "" +"Tawny generates an ortho mosaic ortho that will be draped over the densified " +"cloud." + +#: aperodedenis.py:1708 +msgid "Saisir si besoin les paramètres facultatifs, exemple :" +msgstr "Enter optional settings here. For instance:" + +#: aperodedenis.py:1711 +msgid "Liste des paramètres facultatifs nommés :" +msgstr "Named optional settings list:" + +#: aperodedenis.py:1715 +msgid "Tracer un masque sur la mosaïque Tarama" +msgstr "Plot a mask on the Tarama mosaic" + +#: aperodedenis.py:1721 +msgid "La saisie des masques n'est active qu'aprés Tapas." +msgstr "Draw masks is only activated after Tapas." + +#: aperodedenis.py:1722 aperodedenis.py:2861 aperodedenis.py:4405 +#: aperodedenis.py:4406 +msgid "Pas de masque." +msgstr "No mask" + +#: aperodedenis.py:1725 +msgid "" +"Pour supprimer un masque : supprimer la maitresse dans l'option GeomImage" +msgstr "To remove a mask: remove the mistress in the GeomImage option" + +#: aperodedenis.py:1726 +msgid "Remarque : les masques sont communs à GeomImage et AperoDeDenis" +msgstr "Note: masks are common to GeomImage and AperoDeDenis" + +#: aperodedenis.py:1727 +msgid "Consulter la documentation." +msgstr "Consult the documentation." + +#: aperodedenis.py:1755 +msgid "Statue - avec drapage" +msgstr "Statue - with drape" + +#: aperodedenis.py:1756 +msgid "QuickMac - rapide, sans drapage" +msgstr "QuickMac - quick, without drape" + +#: aperodedenis.py:1762 +msgid "Tracer le masque 3D sur le nuage AperiCloud" +msgstr "Draw 3D mask on the cloud of AperiCloud" + +#: aperodedenis.py:1764 +msgid "Supprimer le masque 3D" +msgstr "Delete the 3D mask" + +#: aperodedenis.py:1767 +msgid "Dans l'outil : " +msgstr "In the tool:" + +#: aperodedenis.py:1768 +msgid "Définir le masque : F9 " +msgstr "Define the mask: F9" + +#: aperodedenis.py:1769 +msgid "Ajouter un point : clic gauche" +msgstr "Add a point: left click" + +#: aperodedenis.py:1770 +msgid "Fermer le polygone : clic droit" +msgstr "Close the polygon: right click" + +#: aperodedenis.py:1771 +msgid "Sélectionner : touche espace" +msgstr "Select: space" + +#: aperodedenis.py:1772 +msgid "Sauver le masque : Ctrl S." +msgstr "Save mask: Ctrl S" + +#: aperodedenis.py:1773 +msgid "Quitter : Ctrl Q." +msgstr "Exit: Ctrl A" + +#: aperodedenis.py:1774 +msgid "Agrandir les points : Maj +" +msgstr "Enlarge points: Maj +" + +#: aperodedenis.py:1775 +msgid "Saisie simultanée de plusieurs masques disjoints possible" +msgstr "Simultaneous multiple disjoint masks draw possible." + +#: aperodedenis.py:1776 +msgid "C3DC a la priorité sur le masque 2D de Malt" +msgstr "C3DC has priority over Malt's 2D mask" + +#: aperodedenis.py:1794 +msgid " Valider les options" +msgstr "Confirm options" + +#: aperodedenis.py:1797 aperodedenis.py:1819 aperodedenis.py:1877 +#: aperodedenis.py:1924 aperodedenis.py:1998 aperodedenis.py:2025 +msgid " Annuler" +msgstr " Abort" + +#: aperodedenis.py:1810 +msgid "Indiquer les dimensions du capteur, en mm." +msgstr "Enter the dimensions of the sensor, in mm" + +#: aperodedenis.py:1811 +msgid "par exemple :" +msgstr "for instance:" + +#: aperodedenis.py:1812 +msgid "Le site :" +msgstr "Website:" + +#: aperodedenis.py:1813 +msgid "fournit les dimensions de tous les appareils photos." +msgstr "Provides dimensions of all cameras." + +#: aperodedenis.py:1816 aperodedenis.py:1874 aperodedenis.py:2022 +msgid " Valider" +msgstr " Confirm" + +#: aperodedenis.py:1852 aperodedenis.py:1978 +msgid "Marque de l'appareil : " +msgstr "Brand of the camera" + +#: aperodedenis.py:1856 +msgid "Nom de la camera : " +msgstr "Name of the camera : " + +#: aperodedenis.py:1860 aperodedenis.py:1986 +msgid "Focale en mm:" +msgstr "Focal length in mm :" + +#: aperodedenis.py:1864 aperodedenis.py:1990 +msgid "Focale équivalente 35mm :" +msgstr "Equivalent focal length 35mm:" + +#: aperodedenis.py:1868 +msgid "Nombre d'images à conserver par seconde :" +msgstr "Number of pictures to record per second:" + +#: aperodedenis.py:1910 aperodedenis.py:1933 +msgid "linéaire" +msgstr "linear" + +#: aperodedenis.py:1911 +msgid "cubique" +msgstr "cubic" + +#: aperodedenis.py:1914 +msgid " Choisir la méthode d'interpolation " +msgstr " Choose the interpolation method" + +#: aperodedenis.py:1916 +msgid " Choisir le pas du maillage " +msgstr " Choose the steps of the mesh." + +#: aperodedenis.py:1921 aperodedenis.py:1954 +msgid "Valider " +msgstr "Confirm" + +#: aperodedenis.py:1950 +msgid "Choisir profil à afficher " +msgstr "Choose the profile to display" + +#: aperodedenis.py:1957 +msgid "Annuler " +msgstr "Abort" + +#: aperodedenis.py:1978 +msgid "Modification des Exif" +msgstr "Exif edit" + +#: aperodedenis.py:1982 +msgid "Modèle de l'appareil: " +msgstr "Camera model:" + +#: aperodedenis.py:1995 +msgid "Valider et mettre à jour" +msgstr "Confirm and update" + +#: aperodedenis.py:2017 +msgid "Indiquer le nombre de photos à retenir." +msgstr "How many pictures to select ?" + +#: aperodedenis.py:2018 +msgid "" +"Un nouveau chantier sera créé avec les photos ayant, par paire, le plus de " +"points homologues" +msgstr "" +"A new project will be created with the photos having, by pairs, the more tie-" +"points" + +#: aperodedenis.py:2019 +msgid "Ce choix est différent du nombre moyen de points homologues par photo." +msgstr "" +"This ranking is different from the average number of corresponding tie-point " +"per photo." + +#: aperodedenis.py:2040 +msgid "MicMac est une réalisation de l'IGN" +msgstr "MicMac was realised by IGN" + +#: aperodedenis.py:2327 +msgid "Quelles options par défaut utiliser pour les nouveaux chantiers ?" +msgstr "Which default options do you want to use for new projects ?" + +#: aperodedenis.py:2328 +msgid "Les options par défaut concernent :" +msgstr "Default options relates:" + +#: aperodedenis.py:2329 +msgid "Tapioca : All, MulScale, line ,les échelles et delta" +msgstr "Tapioca: All, MulScale, line ,scales and delta" + +#: aperodedenis.py:2330 +msgid "Tapas : RadialExtended,RadialStandard, Radialbasic, arrêt aprés Tapas" +msgstr "Tapas: RadialExtended,RadialStandard, Radialbasic, stop after Tapas" + +#: aperodedenis.py:2331 +msgid "Malt : mode, zoom final, nombre de photos autour de la maîtresse" +msgstr "Malt: mode, final zoom, number of pictures around master picture" + +#: aperodedenis.py:2332 +msgid "Tawny et ses options en saisie libre" +msgstr "Tawny and its free entry options" + +#: aperodedenis.py:2333 +msgid "C3DC : mode (Statue ou QuickMac)" +msgstr "C3DC: mode (Statue or QuickMac)" + +#: aperodedenis.py:2372 +msgid "Pas de répertoire pour les photos" +msgstr "No pictures directory" + +#: aperodedenis.py:2473 aperodedenis.py:2495 +msgid "Enregistrer le chantier ?" +msgstr "Save project ?" + +#: aperodedenis.py:2474 aperodedenis.py:2496 +msgid "Chantier non encore enregistré. Voulez-vous l'enregistrer ?" +msgstr "Project not saved. Do you want to save it?" + +#: aperodedenis.py:2475 aperodedenis.py:2483 aperodedenis.py:2497 +#: aperodedenis.py:2504 aperodedenis.py:8982 +msgid "Enregistrer" +msgstr "Save" + +#: aperodedenis.py:2476 aperodedenis.py:2484 aperodedenis.py:2498 +#: aperodedenis.py:2505 aperodedenis.py:8982 +msgid "Ne pas enregistrer." +msgstr "Don't save" + +#: aperodedenis.py:2478 aperodedenis.py:2486 aperodedenis.py:2500 +#: aperodedenis.py:2507 aperodedenis.py:8984 +msgid "Chantier précédent enregistré : %s" +msgstr "Last project saved: %s" + +#: aperodedenis.py:2481 aperodedenis.py:2502 aperodedenis.py:8980 +msgid "Enregistrer le chantier %s ?" +msgstr "Save project %s?" + +#: aperodedenis.py:2482 aperodedenis.py:2503 aperodedenis.py:8981 +msgid "" +"Chantier modifié depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?" +msgstr "Project not saved. Do you want to save it?" + +#: aperodedenis.py:2508 +msgid "Choisir un chantier." +msgstr "Select a project." + +#: aperodedenis.py:2510 aperodedenis.py:6542 +msgid "Aucun chantier choisi." +msgstr "No selected project." + +#: aperodedenis.py:2518 aperodedenis.py:6561 aperodedenis.py:6565 +msgid "Chantier choisi %s corrompu. Abandon." +msgstr "" +"Selected project %s corrupted. Aborting\n" +"." + +#: aperodedenis.py:2522 +msgid "Chantier enregistré" +msgstr "Project saved." + +#: aperodedenis.py:2527 +msgid "Indiquer les photos à traiter avant d'enregistrer le chantier." +msgstr "Select the pictures to process before saving project." + +#: aperodedenis.py:2537 +msgid "Commencer par choisir les photos" +msgstr "Start by choosing the pictures." + +#: aperodedenis.py:2537 +msgid "Il n'a pas encore de nom, il ne peut être renommé." +msgstr "It has no name yet, so he can't be renamed." + +#: aperodedenis.py:2537 +msgid "Le chantier est en cours de définition." +msgstr "The project is being defined." + +#: aperodedenis.py:2539 +msgid "Nouveau nom ou nouveau chemin pour le chantier %s :" +msgstr "New name or path for the project %s:" + +#: aperodedenis.py:2540 +msgid "Tout chemin relatif au chemin actuel est valide" +msgstr "All relative path to actual path is valid." + +#: aperodedenis.py:2541 +msgid "Un chemin absolu sur la même unité disque est valide" +msgstr "An absolute path on the same disk is valid." + +#: aperodedenis.py:2542 +msgid "Aucun fichier de l'arborescence du chantier ne doit être ouvert." +msgstr "No files from the tree of the project must be opened." + +#: aperodedenis.py:2553 +msgid "Le nom du nouveau chantier %s existe déjà. Abandon." +msgstr "The choosen name for the project %s already exists. Aborting." + +#: aperodedenis.py:2556 +msgid "Le nouveau répertoire " +msgstr "The new directory" + +#: aperodedenis.py:2556 +msgid "Utiliser l'Export-Import." +msgstr "Use export-import." + +#: aperodedenis.py:2556 +msgid "implique un changement de disque." +msgstr "imply a disk change." + +#: aperodedenis.py:2559 +msgid "pour le chantier est déjà utilisé." +msgstr "for the project is already used." + +#: aperodedenis.py:2559 aperodedenis.py:2562 +msgid "Choisissez un autre nom." +msgstr "Choose another name." + +#: aperodedenis.py:2559 aperodedenis.py:2562 +msgid "Le répertoire" +msgstr "The directory" + +#: aperodedenis.py:2562 +msgid "désigne un sous-répertoire du chantier en cours." +msgstr "designate a sub-directory of the current project." + +#: aperodedenis.py:2574 +msgid "Le renommage du chantier ne peut se faire actuellement," +msgstr "Can't rename the project now," + +#: aperodedenis.py:2574 +msgid "soit le nom fourni est incorrect," +msgstr "either the name is incorrect," + +#: aperodedenis.py:2575 +msgid "soit un fichier du chantier est ouvert par une autre application." +msgstr "or a file from the project is opened by anoter application." + +#: aperodedenis.py:2576 +msgid "erreur : " +msgstr "error:" + +#: aperodedenis.py:2576 +msgid "soit l'explorateur explore l'arborescence." +msgstr "or the explorer is in the tree." + +#: aperodedenis.py:2592 +msgid "Chantier :" +msgstr "Project:" + +#: aperodedenis.py:2592 +msgid "Répertoire : " +msgstr "Directory:" + +#: aperodedenis.py:2592 +msgid "renommé en :" +msgstr "renamed into:" + +#: aperodedenis.py:2648 +msgid "Pas de chantier en cours" +msgstr "No current project" + +#: aperodedenis.py:2650 +msgid "Patience : chantier en cours d'archivage..." +msgstr "Please wait: the project is being archived." + +#: aperodedenis.py:2652 +msgid "Archive " +msgstr "Archive" + +#: aperodedenis.py:2652 +msgid "Taille =" +msgstr "Size =" + +#: aperodedenis.py:2652 +msgid "créée sous " +msgstr "created in" + +#: aperodedenis.py:2657 +msgid "Choisir le nom de l'archive à importer." +msgstr "Choose the name of the archive to import." + +#: aperodedenis.py:2659 +msgid "Export" +msgstr "Export" + +#: aperodedenis.py:2660 +msgid "Chantier à importer" +msgstr "Project to import." + +#: aperodedenis.py:2662 +msgid "Importation abandonnée." +msgstr "Import aborted." + +#: aperodedenis.py:2665 +msgid " n'est pas un fichier d'export valide" +msgstr "is not a valid export file" + +#: aperodedenis.py:2666 +msgid "ou alors, sous ubuntu,il lui manque le droit d'exécution." +msgstr "" +"or if you use unbuntu, you probably don't have the execution permission." + +#: aperodedenis.py:2670 +msgid "Choisir le répertoire dans lequel recopier le chantier." +msgstr "Select the directory in which you want to copy the project." + +#: aperodedenis.py:2674 +msgid " n'est pas un répertoire valide." +msgstr "is not a valid directory." + +#: aperodedenis.py:2677 +msgid "Patience !" +msgstr "Please wait !" + +#: aperodedenis.py:2677 +msgid "Recopie en cours dans" +msgstr "Copying in" + +#: aperodedenis.py:2685 +msgid "Le répertoire destination" +msgstr "Destination directory" + +#: aperodedenis.py:2685 +msgid "existe déjà. Abandon" +msgstr "already exists. Aborting" + +#: aperodedenis.py:2696 aperodedenis.py:2705 +msgid "Erreur copie lors d'un import : " +msgstr "Copy error during an import:" + +#: aperodedenis.py:2697 aperodedenis.py:2706 +msgid "L'importation a échouée. Erreur : " +msgstr "Import failed. Error:" + +#: aperodedenis.py:2721 +msgid " absent" +msgstr " missing" + +#: aperodedenis.py:2737 +msgid "Chantier importé :" +msgstr "Imported project:" + +#: aperodedenis.py:2737 +msgid "Répertoire :" +msgstr "Directory:" + +#: aperodedenis.py:2737 +msgid "Vous pouvez le renommer si besoin." +msgstr "You can rename it if necessary" + +#: aperodedenis.py:2740 +msgid "Version de MicMac avant l'import : %s" +msgstr "MicMac version before import:" + +#: aperodedenis.py:2741 +msgid "Version de MicMac : %s" +msgstr "MicMac version: %s" + +#: aperodedenis.py:2744 +msgid "erreur affichage version lors de l'import d'un chantier : " +msgstr "Error display version when importing a project:" + +#: aperodedenis.py:2746 +msgid "Anomalie lors de l'importation : " +msgstr "Anomaly when importing:" + +#: aperodedenis.py:2754 +msgid "erreur copie fichier param chantier : %(param)s vers %(rep)s erreur=" +msgstr "Error copying project settings file: %(param)s to %(rep)s error:" + +#: aperodedenis.py:2757 +msgid "Erreur lors de la copie du fichier paramètre chantier" +msgstr "Error when copying project settings file " + +#: aperodedenis.py:2757 +msgid "erreur :" +msgstr "error:" + +#: aperodedenis.py:2757 +msgid "vers" +msgstr "to" + +#: aperodedenis.py:2779 +msgid "Répertoire des photos :" +msgstr "Pictures directory:" + +#: aperodedenis.py:2781 +msgid "Répertoire de la vidéo :" +msgstr "Video directory:" + +#: aperodedenis.py:2783 +msgid "Aucune photo sélectionnée." +msgstr "No pictures selected." + +#: aperodedenis.py:2786 +msgid " photos sélectionnées" +msgstr " selected pictures" + +#: aperodedenis.py:2786 +msgid "(sans calibration si tapas executé) : " +msgstr "(without calibration if Tapas executed)" + +#: aperodedenis.py:2788 +msgid " photos sélectionnées : " +msgstr " pictures selected:" + +#: aperodedenis.py:2791 +msgid "ATTENTION : plusieurs extensions différentes dans les photos choisies !" +msgstr "Warning: several extensions formats choosen in selected pictures !" + +#: aperodedenis.py:2791 +msgid "Le traitement ne se fera que sur un type de fichier." +msgstr "Processing can be done on only one file type." + +#: aperodedenis.py:2796 aperodedenis.py:2810 aperodedenis.py:2850 +msgid "Mode : " +msgstr "Mod: " + +#: aperodedenis.py:2798 aperodedenis.py:2800 +msgid "Echelle 1 : " +msgstr "Scale 1:" + +#: aperodedenis.py:2801 +msgid "Echelle 2 : " +msgstr "Scale 2:" + +#: aperodedenis.py:2803 +msgid "Echelle : " +msgstr "Scale:" + +#: aperodedenis.py:2804 +msgid "Delta : " +msgstr "Delta:" + +#: aperodedenis.py:2812 +msgid "Nombre de photos pour calibration intrinsèque : " +msgstr "Number of pictures for intrinsic calibration:" + +#: aperodedenis.py:2814 +msgid "Ces photos servent uniquement à la calibration." +msgstr "These pictures will be used for calibration only." + +#: aperodedenis.py:2816 +msgid "Tarama demandé aprés Tapas" +msgstr "Tarama requested after Tapas" + +#: aperodedenis.py:2818 +msgid "Arrêt demandé après Tapas" +msgstr "Stop asked after Tapas." + +#: aperodedenis.py:2823 +msgid "Calibration présente" +msgstr "Existing calibration." + +#: aperodedenis.py:2826 +msgid "Calibration annulée : distance=0" +msgstr "Aborted calibration: distance = 0" + +#: aperodedenis.py:2828 +msgid "Calibration incomplète :" +msgstr "Incomplete calibration:" + +#: aperodedenis.py:2840 +msgid "C3DC : Masque 3D" +msgstr "C3DC: 3D mask" + +#: aperodedenis.py:2844 +msgid "La version installée de Micmac n'autorise pas les masques en 3D" +msgstr "MicMac's installed version does not allow 3D mask" + +#: aperodedenis.py:2853 +msgid "Pas d'image maîtresse" +msgstr "No master picture" + +#: aperodedenis.py:2855 aperodedenis.py:2875 +msgid "Image maîtresse : " +msgstr "Master picture:" + +#: aperodedenis.py:2857 aperodedenis.py:2877 aperodedenis.py:4399 +#: aperodedenis.py:4402 +msgid " images maîtresses" +msgstr "Master pictures:" + +#: aperodedenis.py:2859 +msgid "1 masque" +msgstr "One mask" + +#: aperodedenis.py:2863 aperodedenis.py:4413 aperodedenis.py:4414 +msgid " masques" +msgstr "masks" + +#: aperodedenis.py:2865 +msgid "%s photos utiles autour de la maîtresse" +msgstr "%s useful photos around the mistress" + +#: aperodedenis.py:2866 +msgid "les meilleures photos en correspondances seront choisies" +msgstr "The best photos in matches will be chosen" + +#: aperodedenis.py:2870 +msgid "Tawny lancé aprés Malt" +msgstr "Tawny launched after Malt" + +#: aperodedenis.py:2879 +msgid "arrêt au zoom : " +msgstr "Stop at zoom level: " + +#: aperodedenis.py:2884 +msgid "Chantier en cours de définition." +msgstr "The project is beig defined." + +#: aperodedenis.py:2888 +msgid "Chantier : " +msgstr "Project: " + +#: aperodedenis.py:2895 +msgid "Chemin du chantier :" +msgstr "Project path:" + +#: aperodedenis.py:2897 +msgid "Chantier en attente d'enregistrement." +msgstr "Project waiting to be saved." + +#: aperodedenis.py:2899 +msgid "Chantier enregistré." +msgstr "Project saved." + +#: aperodedenis.py:2901 +msgid "Options du chantier modifiables." +msgstr "Project options editable." + +#: aperodedenis.py:2903 +msgid "Chantier interrompu suite à erreur." +msgstr "Project interrupted by an error." + +#: aperodedenis.py:2903 +msgid "Relancer micmac." +msgstr "Relaunch MicMac." + +#: aperodedenis.py:2905 +msgid "Options de Malt/C3DC modifiables." +msgstr "Malt/C3DC options editable." + +#: aperodedenis.py:2907 +msgid "Chantier terminé." +msgstr "Project completed." + +#: aperodedenis.py:2909 +msgid "Chantier exécuté puis débloqué." +msgstr "Project executed and unblocked." + +#: aperodedenis.py:2915 +msgid "Nuage de point non densifié généré après Tapas." +msgstr "Undensified point cloud generated after Tapas." + +#: aperodedenis.py:2919 +msgid "Nuage de point densifié généré après %s" +msgstr "Densified point cloud generated after %s" + +#: aperodedenis.py:2922 +msgid "Aucun nuage de point généré." +msgstr "No point cloud generated." + +#: aperodedenis.py:2929 +msgid "Les caractéristiques du chantier précédent" +msgstr "Characteristics from last project " + +#: aperodedenis.py:2929 +msgid "n'ont pas pu être lues correctement." +msgstr "couldn't be read properly." + +#: aperodedenis.py:2930 +msgid "" +"Le fichier des paramètres est probablement incorrect ou vous avez changé la " +"version de l'interface." +msgstr "Settings files is incorrect or GUI's version has changed." + +#: aperodedenis.py:2931 +msgid "Certaines fonctions seront peut_être défaillantes." +msgstr "Some functions will maybe fail." + +#: aperodedenis.py:2932 +msgid "Désolé pour l'incident." +msgstr "Sorry for the inconvenience." + +#: aperodedenis.py:2933 +msgid "Erreur : " +msgstr "Error:" + +#: aperodedenis.py:2961 aperodedenis.py:2962 aperodedenis.py:2965 +msgid "Toutes les photos" +msgstr "All pictures" + +#: aperodedenis.py:2964 +msgid "Toutes les photos utiles" +msgstr "All useful pictures" + +#: aperodedenis.py:2965 +msgid "sans les %s photos pour calibration intrinseque" +msgstr "without %s pictures for intrinsic calibration." + +#: aperodedenis.py:2971 aperodedenis.py:2982 aperodedenis.py:2993 +#: aperodedenis.py:3005 aperodedenis.py:3020 aperodedenis.py:3043 +#: aperodedenis.py:3067 aperodedenis.py:3084 aperodedenis.py:3095 +#: aperodedenis.py:3113 aperodedenis.py:3132 aperodedenis.py:8481 +#: aperodedenis.py:8498 +msgid "Fermer" +msgstr "Close" + +#: aperodedenis.py:2976 +msgid "Aucun point GPS saisi." +msgstr "No GPS point entered." + +#: aperodedenis.py:2979 +msgid "Affichage des photos avec points GPS" +msgstr "Display pictures with GPS points." + +#: aperodedenis.py:2981 +msgid "seules les photos avec points sont montrées." +msgstr "Only pictures with points will be displayed." + +#: aperodedenis.py:2990 +msgid "Liste des images maîtresses et des masques " +msgstr "List of master pictures and masks" + +#: aperodedenis.py:2990 +msgid "communs à GeomImage et AperoDedenis" +msgstr "Common to GeomImage and AperoDedenis" + +#: aperodedenis.py:2992 +msgid "Images maîtresses et masques" +msgstr "Master picture and masks" + +#: aperodedenis.py:2996 +msgid "Pas de maîtresses définies pour ce chantier" +msgstr "No master picture defined for this project" + +#: aperodedenis.py:3002 +msgid "Mosaique Tarama et masque " +msgstr "Tarama : mosaic ans mask" + +#: aperodedenis.py:3002 +msgid "Option Ortho de Malt" +msgstr "Option Ortho for Malt" + +#: aperodedenis.py:3004 +msgid "Image maîtresse et masque" +msgstr "Master picture and mask" + +#: aperodedenis.py:3011 +msgid "Pas de masque 3D pour ce chantier." +msgstr "No 3D mask for this project." + +#: aperodedenis.py:3018 +msgid "Visaliser le masque 3D" +msgstr "Display 3D mask" + +#: aperodedenis.py:3022 +msgid "Affichage du masque 3D :" +msgstr "Viewing 3D mask:" + +#: aperodedenis.py:3023 +msgid "Les points blancs du nuage sont dans le masque" +msgstr "Point cloud's white point are in the mask" + +#: aperodedenis.py:3024 +msgid "Ce masque C3DC a la priorité sur le masque 2D de Malt" +msgstr "C3DC mask has priority over 2D mask from Malt" + +#: aperodedenis.py:3025 +msgid "ATTENTION : pour continuer FERMER la fenêtre 3D" +msgstr "Warning : to continue close windows 3D." + +#: aperodedenis.py:3026 +msgid "puis cliquer si besoin sur le bouton FERMER ci-dessus." +msgstr "Then click on the CLOSE button above." + +#: aperodedenis.py:3036 +msgid "horizontale" +msgstr "horizontal" + +#: aperodedenis.py:3038 +msgid "verticale" +msgstr "vertical" + +#: aperodedenis.py:3040 +msgid "Visualiser l'image maîtresse et le plan horizontal ou vertical" +msgstr "Display master picture and horizontal or vertical plane" + +#: aperodedenis.py:3042 +msgid "Zone plane " +msgstr "Plane area" + +#: aperodedenis.py:3048 +msgid "Pas de plan horizontal ou vertical défini pour ce chantier" +msgstr "No horizontal or vertical plane defined for this project." + +#: aperodedenis.py:3058 +msgid "HORIZONTALE" +msgstr "HORIZONTAL" + +#: aperodedenis.py:3061 +msgid "VERTICALE" +msgstr "VERTICAL" + +#: aperodedenis.py:3064 +msgid "Affichage des photos avec ligne horizontale ou verticale" +msgstr "Display pictures with horizontal or vertical plane" + +#: aperodedenis.py:3066 +msgid "ligne " +msgstr "line" + +#: aperodedenis.py:3070 +msgid "Pas de ligne horizontale ou verticale définie pour ce chantier" +msgstr "No horizontal or vertical line defined for this project" + +#: aperodedenis.py:3076 +msgid "Pas de distance correcte définie pour ce chantier." +msgstr "No correct distance defined for this project." + +#: aperodedenis.py:3081 +msgid "Visualiser les photos avec distance" +msgstr "Display pictures with distance" + +#: aperodedenis.py:3083 +msgid "Valeur de la distance : " +msgstr "Distance value:" + +#: aperodedenis.py:3089 +msgid "Pas de photos pour la calibration intrinsèque par Tapas." +msgstr "No pictures for intrinsic calibration by Tapas." + +#: aperodedenis.py:3092 +msgid "Les photos pour calibration intrinsèque (Tapas)" +msgstr "Pictures for intrinsic calibration (Tapas)" + +#: aperodedenis.py:3094 +msgid "Calibration intrinsèque" +msgstr "Intrinsic calibration" + +#: aperodedenis.py:3100 +msgid "Pas de mosaique. Choisir l'option Tarama de tapas." +msgstr "No mosaic. Choose Tarama's option of Tapas." + +#: aperodedenis.py:3106 +msgid "Echec de la conversion mosaique en JPG." +msgstr "Failed mosaic conversion to JPG." + +#: aperodedenis.py:3110 +msgid "Mosaique créée par Tarama" +msgstr "Mosaic generates by Tarama" + +#: aperodedenis.py:3118 +msgid "Pas d' ortho mosaique par Tawny. Choisir l'option Tawny de Malt." +msgstr "No mosaic. Choose Tawny's option of Malt" + +#: aperodedenis.py:3125 +msgid "Echec de la conversion de la mosaïque TIF en JPG." +msgstr "Failed mosaic conversion to JPG." + +#: aperodedenis.py:3129 +msgid "Ortho mosaique créée par Tawny" +msgstr "Ortho Mosaic generates by Tawny." + +#: aperodedenis.py:3156 +msgid "Pas de trace de la trace !" +msgstr "No log found !" + +#: aperodedenis.py:3167 +msgid "Pas de nuage de points aprés Tapas." +msgstr "No point cloud after Tapas." + +#: aperodedenis.py:3169 +msgid "Programme pour ouvrir les .PLY non trouvéé." +msgstr ".PLY opener program not found." + +#: aperodedenis.py:3174 aperodedenis.py:5386 +msgid "Pas de nuage de points aprés Malt ou C3DC." +msgstr "No point cloud after Malt or C3DC." + +#: aperodedenis.py:3176 aperodedenis.py:5388 +msgid "Programme pour ouvrir les .PLY non trouvé." +msgstr ".PLY opener program not found." + +#: aperodedenis.py:3182 +msgid "Répertoire bin de MicMac : " +msgstr "Directory of MicMac\\bin:" + +#: aperodedenis.py:3184 +msgid "Version MicMac :" +msgstr "MicMac version:" + +#: aperodedenis.py:3186 +msgid "Outil exiftool :" +msgstr "exiftool tool:" + +#: aperodedenis.py:3188 +msgid "Outil convert d'ImageMagick :" +msgstr "Convert ImageMagick tool:" + +#: aperodedenis.py:3190 +msgid "Outil pour afficher les .ply :" +msgstr "Tool used to display .ply:" + +#: aperodedenis.py:3192 +msgid "Outil pour décompacter les vidéos (ffmpeg):" +msgstr "Toll used to unpack videos (ffmpeg):" + +#: aperodedenis.py:3194 +msgid "Répertoire d'AperoDeDenis :" +msgstr "AperoDeDenis's directory:" + +#: aperodedenis.py:3196 +msgid "Répertoire des paramètres :" +msgstr "Settings directory:" + +#: aperodedenis.py:3206 +msgid "Répertoire bin sous MICMAC : " +msgstr "Directory of MicMac\\bin:" + +#: aperodedenis.py:3215 +msgid "Désigner le répertoire bin sous Micmac " +msgstr "Designate the directory of MicMac\\bin:" + +#: aperodedenis.py:3218 aperodedenis.py:3225 +msgid "Répertoire bin de Micmac :" +msgstr "Directory of MicMac\\bin: " + +#: aperodedenis.py:3218 aperodedenis.py:3225 aperodedenis.py:3338 +#: aperodedenis.py:3359 aperodedenis.py:3379 aperodedenis.py:3400 +msgid "Abandon, pas de changement." +msgstr "Abort, no change." + +#: aperodedenis.py:3223 +msgid "" +"Le chemin du répertoire bin de micmac ne doit pas comporter le caractère " +"'espace'." +msgstr "" +"The path of the directory of MicMac\\bin must not include the 'space' " +"character. " + +#: aperodedenis.py:3224 +msgid "Renommer le répertoire de MicMac." +msgstr "Rename the MicMac's directory." + +#: aperodedenis.py:3239 +msgid "Le répertoire %s ne contient pas le fichier mm3d.exe. Abandon" +msgstr "The %s directory does not contain the mm3d.exe file. abort" + +#: aperodedenis.py:3286 +msgid "Le répertoire %s ne contient pas le fichier mm3d. Abandon" +msgstr "The % s directory does not contain the mm3d file. Abort" + +#: aperodedenis.py:3299 +msgid "Nouveau répertoire de Micmac :" +msgstr "New MicMac's directory:" + +#: aperodedenis.py:3304 +msgid "Le programme mm3d est présent mais ne peut s'exécuter." +msgstr "mm3d found but can't be executed." + +#: aperodedenis.py:3304 +msgid "Vérifier si la version est compatible avec le système. :" +msgstr "Please check if the current version is compatible with this system." + +#: aperodedenis.py:3306 +msgid "Abandon." +msgstr "Aborting." + +#: aperodedenis.py:3306 +msgid "Le programme mm3d est absent du répertoire choisi :" +msgstr "MM3d is not to be found in the choosen directory:" + +#: aperodedenis.py:3306 +msgid "Répertoire bin sous MicMac incorrect." +msgstr "Wrong directory for MicMac\\bin. " + +#: aperodedenis.py:3311 +msgid "Chemin de exiftool :" +msgstr "exiftool path:" + +#: aperodedenis.py:3313 +msgid "Chemin de convert d'image Magick :" +msgstr "ImageMafick's convert path:" + +#: aperodedenis.py:3315 +msgid "Chemin de ffmpeg :" +msgstr "Path to ffmpeg" + +#: aperodedenis.py:3320 +msgid "Pas de version identifiée de MicMac" +msgstr "Not identificated version of MicMac" + +#: aperodedenis.py:3321 +msgid "Nouvelle version de MicMac : " +msgstr "New version of MicMac:" + +#: aperodedenis.py:3328 +msgid "Pas de chemin pour le programme exiftool" +msgstr "No path for exiftool program" + +#: aperodedenis.py:3330 aperodedenis.py:3343 +msgid "Programme exiftool :" +msgstr "Exiftool program: " + +#: aperodedenis.py:3336 +msgid "Recherche exiftool" +msgstr "exiftool search" + +#: aperodedenis.py:3338 +msgid "Fichier exiftool inchangé :" +msgstr "Exiftool file unchanged." + +#: aperodedenis.py:3349 +msgid "Pas de chemin pour le programme convert d'ImageMagick" +msgstr "No patch for ImageMagick's convert program" + +#: aperodedenis.py:3351 aperodedenis.py:3364 +msgid "Programme convert :" +msgstr "Convert program:" + +#: aperodedenis.py:3357 +msgid "Recherche convert" +msgstr "Convert search" + +#: aperodedenis.py:3359 +msgid "Fichier convert inchangé :" +msgstr "Exiftool file unchanged:" + +#: aperodedenis.py:3370 +msgid "Pas de chemin pour le programme ouvrant les .PLY" +msgstr "No patch for the .PLY opener program. " + +#: aperodedenis.py:3372 aperodedenis.py:3384 +msgid "Programme ouvrant les .PLY :" +msgstr ".PLY opener program:" + +#: aperodedenis.py:3376 +msgid "meshlab ou CloudCompare" +msgstr "meshlab or CloudCompare" + +#: aperodedenis.py:3377 +msgid "Recherche fichier Meshlab sous VCG, ou CloudCompare" +msgstr "Meshlab under VCG or CloudCompare file search" + +#: aperodedenis.py:3379 +msgid "Fichier Meshlab ou cloud compare :" +msgstr "Meshlab or CloudCompare file:" + +#: aperodedenis.py:3390 +msgid "Pas de chemin pour le programme Ffmpeg" +msgstr "No path for ffmpeg program" + +#: aperodedenis.py:3392 aperodedenis.py:3405 +msgid "Programme ffmpeg :" +msgstr "ffmpeg program:" + +#: aperodedenis.py:3398 +msgid "Recherche ffmpeg" +msgstr "ffmpeg search:" + +#: aperodedenis.py:3400 +msgid "Fichier ffmpeg inchangé :" +msgstr "ffmpeg file unchanged." + +#: aperodedenis.py:3411 +msgid "Tacky message au lancement activé" +msgstr "Launching tacky message activated." + +#: aperodedenis.py:3413 +msgid "Tacky message au lancement désactivé" +msgstr "Launching tacky message desactivated." + +#: aperodedenis.py:3417 +msgid "Sélectionnez la langue à utiliser. L'application sera redémarrée." +msgstr "" +"Select the language you want to use. The application will be restarted." + +#: aperodedenis.py:3425 +msgid "Appliquer" +msgstr "Apply" + +#: aperodedenis.py:3428 aperodedenis.py:3434 +msgid "Français" +msgstr "French" + +#: aperodedenis.py:3429 +msgid "Anglais" +msgstr "English" + +#: aperodedenis.py:3454 +msgid "" +"Avant de choisir les photos associer le répertoire bin de micmac (Menu " +"Paramétrage\\associer le répertoire bin de MicMac)." +msgstr "" +"Please link the MicMac\\bin directory before choosing pictures (Settings menu" +"\\Link the MicMac\\bin directory)." + +#: aperodedenis.py:3458 +msgid "" +"Avant de choisir les photos associer le chemin du programme exiftool (Menu " +"trage\\Associer exiftool)." +msgstr "" +"Please association the exiftool programm directory before choosing pictures " +"(Settings menu\\Link the 'exiftool' directory)." + +#: aperodedenis.py:3466 +msgid "Nouvelles photos pour le meme chantier" +msgstr "New pictures for the same project" + +#: aperodedenis.py:3467 +msgid "Choisir de nouvelles photos réinitialisera le chantier." +msgstr "Choosing new pictures will reset the project." + +#: aperodedenis.py:3468 +msgid "Les traces et l'arborescence des calculs seront effacées." +msgstr "Logs and calculations tree will be deleted." + +#: aperodedenis.py:3469 +msgid "Les options compatibles avec les nouvelles photos seront conservées." +msgstr "Compatibles options with the new pictures will be preserved." + +#: aperodedenis.py:3471 +msgid "Réinitialiser le chantier" +msgstr "Reset project" + +#: aperodedenis.py:3472 +msgid "Abandon, le chantier n'est pas modifié." +msgstr "Aborting, the project is unchanged." + +#: aperodedenis.py:3482 +msgid "Photos" +msgstr "Pictures" + +#: aperodedenis.py:3486 +msgid "Abandon, aucune sélection de fichier image," +msgstr "Aborting, no picture file selected, " + +#: aperodedenis.py:3486 aperodedenis.py:3550 aperodedenis.py:6248 +msgid "le répertoire et les photos restent inchangés." +msgstr "directory and pictures unchanged." + +#: aperodedenis.py:3490 aperodedenis.py:3513 +msgid "Aucune extension acceptable pour des images. Abandon." +msgstr "No compatible extension for these pictures. Aborting." + +#: aperodedenis.py:3494 +msgid "Impossible dans cette version. Abandon." +msgstr "Impossible in this version. Aborting." + +#: aperodedenis.py:3494 +msgid "Plusieurs extensions différentes :" +msgstr "Several different extensions: " + +#: aperodedenis.py:3499 +msgid "Info : format des photos" +msgstr "Info : pictures format" + +#: aperodedenis.py:3499 +msgid "La version actuelle ne traite que les photos au format JPG," +msgstr "The current version can only process JPG files," + +#: aperodedenis.py:3499 +msgid "or le format des photos est : " +msgstr "but these pictures format is:" + +#: aperodedenis.py:3500 +msgid "les photos vont être converties au format JPG." +msgstr "the pictures will be converted into JPG format." + +#: aperodedenis.py:3501 +msgid "Convertir en JPG" +msgstr "Convert into JPG" + +#: aperodedenis.py:3502 aperodedenis.py:3530 +msgid "Abandonner" +msgstr "Abort" + +#: aperodedenis.py:3505 +msgid "(Menu Paramétrage)" +msgstr "(Settings menu)" + +#: aperodedenis.py:3505 +msgid "Désigner l'outil de conversation 'convert' d'ImageMagick" +msgstr "Designate the ImageMagick's convert conversation tool. " + +#: aperodedenis.py:3527 +msgid "ATTENTION !" +msgstr "WARNING !" + +#: aperodedenis.py:3527 +msgid "" +"ATTENTION : des points GPS ont été précedemment placés sur des photos non " +"choisies pour ce chantier." +msgstr "" +"Warning : some GPS points have been placed on pictures which have not being " +"choosen for this project." + +#: aperodedenis.py:3528 +msgid "" +"Les emplacements de ces points vont être supprimés si vous validez cette " +"sélection de photos." +msgstr "Points location will be deleted if you confirm this picture selection." + +#: aperodedenis.py:3529 +msgid "Valider la sélection de photos" +msgstr "Confirm picture selection" + +#: aperodedenis.py:3538 +msgid "Copie des photos en cours... Patience" +msgstr "Pictures copy... Please wait..." + +#: aperodedenis.py:3547 aperodedenis.py:6245 +msgid "Impossible de créer le répertoire de travail." +msgstr "Impossible to create working directory. " + +#: aperodedenis.py:3547 aperodedenis.py:6245 +msgid "Vérifier les droits en écriture sous le répertoire des photos" +msgstr "Please check write permission on the pictures directory." + +#: aperodedenis.py:3550 aperodedenis.py:6248 +msgid "Aucun JPG, PNG, BMP, TIF, ou GIF sélectionné," +msgstr "No JPG, PNG, BMP, TIF or GIF selected, " + +#: aperodedenis.py:3563 +msgid "L'outil exiftool n'est pas localisé : controle des photos impossible." +msgstr "Exiftool not found: controlling pictures is impossible." + +#: aperodedenis.py:3563 aperodedenis.py:8830 +msgid "Désigner le fichier exiftool (menu paramétrage)." +msgstr "Select the exiftool file (settings menu)" + +#: aperodedenis.py:3565 +msgid "Les focales sont absentes des exif." +msgstr "Focal length absent from exif." + +#: aperodedenis.py:3565 +msgid "Mettez à jour les exifs avant de lancer MicMac." +msgstr "Please update exifs before launching MicMac." + +#: aperodedenis.py:3566 +msgid "Utiliser le menu Outils/Modifier l'exif des photos." +msgstr "Use Tools/Edit pictures exif." + +#: aperodedenis.py:3568 +msgid "Attention : Les focales des photos ou ne sont pas toutes identiques." +msgstr "Warning: the focal length of the pictures are not all the same." + +#: aperodedenis.py:3571 +msgid "Attention : les dimensions des photos ne sont pas toutes identiques." +msgstr "Warning: the dimensions of the pictures are not all the same." + +#: aperodedenis.py:3572 +msgid "Le traitement par MicMac ne sera peut-être pas possible." +msgstr "MicMac's processing will maybe not be possible." + +#: aperodedenis.py:3584 +msgid "De nouvelles photos ont été sélectionnés sur un chantier pré-existant." +msgstr "New pictures were selected on an already existing project." + +#: aperodedenis.py:3585 +msgid "" +"Les anciennes options compatibles avec les nouvelles photos ont été " +"conservées." +msgstr "Former compatibles options with new pictures were preserved." + +#: aperodedenis.py:3635 +msgid "Causes possibles : manque d'espace disque ou droits insuffisants." +msgstr "Possibles causes: no enough space or you don't have the permissions." + +#: aperodedenis.py:3635 +msgid "dans le répertoire " +msgstr "in the directory" + +#: aperodedenis.py:3635 +msgid "erreur lors de la copie du fichier" +msgstr "Error when copying" + +#: aperodedenis.py:3635 +msgid "libellé de l'erreur :" +msgstr "Error:" + +#: aperodedenis.py:3683 +msgid "erreur controle des photos : " +msgstr "Error controlling pictures: " + +#: aperodedenis.py:3713 +msgid "Impossible de créer le répertoire de travail : erreur = " +msgstr "Can't create the work directory, error:" + +#: aperodedenis.py:3727 +msgid "Le chantier est interrompu suite à incident. " +msgstr "The project has been interrupted following an incident." + +#: aperodedenis.py:3728 +msgid "" +"Si besoin créer un nouveau chantier ou débloquer le chantier en lancant " +"micmac." +msgstr "If necessary, create or unblock a project by launching MicMac." + +#: aperodedenis.py:3738 +msgid "Le chantier %(x)s est terminé." +msgstr "The %(x)s project reached his end." + +#: aperodedenis.py:3739 +msgid "Le chantier est terminé après " +msgstr "The project reached his end after" + +#: aperodedenis.py:3740 +msgid "Vous pouvez :" +msgstr "You could:" + +#: aperodedenis.py:3741 +msgid " - Nettoyer le chantier pour modifier les options de Tapioca et Tapas" +msgstr "- Clean project to edit Tapioca and Tapas options" + +#: aperodedenis.py:3742 +msgid "" +" - Conserver les traitements de Tapioca/Tapas pour modifier les options de " +"Malt ou C3DC" +msgstr " - Keep Tapioca/Tapas processif to edit Malt or C3DC options" + +#: aperodedenis.py:3743 +msgid " - Ne rien faire." +msgstr "- Do nothing" + +#: aperodedenis.py:3744 +msgid "Modifier les options de Tapioca et Tapas" +msgstr "Edit Tapioca and Tapas options" + +#: aperodedenis.py:3745 +msgid "Modifier les options de Malt ou C3DC" +msgstr "Edit Malt or C3DC options" + +#: aperodedenis.py:3746 +msgid "Ne rien faire" +msgstr "Do nothing." + +#: aperodedenis.py:3775 aperodedenis.py:4305 +msgid "Nombre de photos choisies : " +msgstr "Number of choosen pictures:" + +#: aperodedenis.py:3801 +msgid "Suppression du masque 3D : la version de MicMac ne comporte pas C3DC" +msgstr "Deleting 3D mask: this MicMac's version does not include C3DC" + +#: aperodedenis.py:3810 +msgid "lancer Micmac pour en constituer un." +msgstr "launch MicMac to generate one." + +#: aperodedenis.py:3810 +msgid "pas de fichier AperiCloud.ply pour construire le masque :" +msgstr "No AperiCloud.ply file to build the mask:" + +#: aperodedenis.py:3815 aperodedenis.py:4588 +msgid "Masque 3D créé" +msgstr "3D mask created" + +#: aperodedenis.py:3817 +msgid "Pas de masque 3D" +msgstr "No 3D mask" + +#: aperodedenis.py:3852 aperodedenis.py:5492 +msgid "Option incorrecte :" +msgstr "Wrong option: " + +#: aperodedenis.py:3865 +msgid "Points GPS non conformes. Nom est absent ou en double. Vérifiez." +msgstr "" +"GPS points nonconforming. Name of point is missing or duplicated. Check." + +#: aperodedenis.py:3872 aperodedenis.py:6472 +msgid "Nom" +msgstr "Name" + +#: aperodedenis.py:3891 +msgid "NomPhoto" +msgstr "PictureName" + +#: aperodedenis.py:3893 aperodedenis.py:3899 +msgid "NomPoint" +msgstr "PointName" + +#: aperodedenis.py:3926 +msgid "Pas de points GPS." +msgstr "No GPS points." + +#: aperodedenis.py:3932 +msgid "%s points GPS placés" +msgstr "%s GPS point placed" + +#: aperodedenis.py:3933 +msgid "pour %s points GPS définis" +msgstr "for %s GPS points given" + +#: aperodedenis.py:3935 +msgid "" +"Attention : il faut au moins 3 points pour qu'ils soient pris en compte." +msgstr "Warning : to consider those, there must be at least three points." + +#: aperodedenis.py:3954 +msgid "" +"Il n'y a pas 3 points placés sur 2 photos : les points GPS seront ignorés." +msgstr "" +"There are no 3 points placed on 2 photos: the GPS points will be ignored." + +#: aperodedenis.py:3957 +msgid "" +"Anomalie : les points suivants ne sont placés que sur une seule photo : " +msgstr "Anomaly: The following points are placed on a single photo:" + +#: aperodedenis.py:3960 +msgid "Anomalie : le point suivant n'est placé que sur une seule photo : " +msgstr "Anomaly: the next point is placed on a single photo:" + +#: aperodedenis.py:3967 +msgid "Attention : plusieurs points GPS ont les mêmes coordonnées." +msgstr "Warning: several GPS points have the same coordinates." + +#: aperodedenis.py:3970 +msgid "Saisie incomplète : les points GPS ne seront pas pris en compte" +msgstr "Incomplete entry: GPS points will not be taken into account" + +#: aperodedenis.py:3985 +msgid "La ligne horizontale ou verticale ne comporte pas 2 points" +msgstr "Horizontal or vertical line does not include two points." + +#: aperodedenis.py:3988 +msgid "Pas de maitre plan horizontal ou vertical" +msgstr "No horizontal or vertcial master plan." + +#: aperodedenis.py:3992 +msgid "Pas de plan horizontal ou vertical" +msgstr "No horizontal or vertical planes" + +#: aperodedenis.py:3997 +msgid "%(x)s Distance %(y)s invalide." +msgstr "%(x)s Distance %(y)s invalid." + +#: aperodedenis.py:3999 +msgid "Calibration annulée." +msgstr "Calibration aborted." + +#: aperodedenis.py:4001 +msgid "%s Pas de distance." +msgstr "%s No distance." + +#: aperodedenis.py:4007 +msgid "La distance n'est pas mesurée par 2 points repérés sur 2 photos." +msgstr "Distance not measured by two points on two pictures." + +#: aperodedenis.py:4010 aperodedenis.py:4013 +msgid "La photo avec distance %s est absente." +msgstr "Picture with distance %s not found." + +#: aperodedenis.py:4015 +msgid "Pas de distance pour la calibration." +msgstr "No distance for calibration." + +#: aperodedenis.py:4032 +msgid "Fichiers" +msgstr "Files" + +#: aperodedenis.py:4123 +msgid "" +"L'échelle pour le mode All de Tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "Scale for Tapioca's All mode invalid, default value, %s, affected." + +#: aperodedenis.py:4127 +msgid "Echelle pour le mode All de Tapioca trop petite :" +msgstr "Scale for Tapiocas's All mode too small." + +#: aperodedenis.py:4127 aperodedenis.py:4166 +msgid "Minimum = 50" +msgstr "Minimum = 50" + +#: aperodedenis.py:4139 +msgid "" +"L'échelle 1 pour MulScale de Tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "" +"Scale 1 from Tapioca's MulScale is invalid, a default value, %s, is affected." + +#: aperodedenis.py:4143 +msgid "Elle est mise à 300." +msgstr "Its value is assigned to 300." + +#: aperodedenis.py:4143 +msgid "L'échelle 1 de MulScale ne doit pas être -1." +msgstr "Scale 1 from MulScal can't be -1." + +#: aperodedenis.py:4150 +msgid "L'échelle 1 pour le mode MulScale de Tapioca est trop petite : " +msgstr "Scale 1 for Tapioca's MulScale mode too small:" + +#: aperodedenis.py:4150 +msgid "Minimum = 50, maximum conseillé : 300" +msgstr "Minimum = 50, indicated maximum = 300" + +#: aperodedenis.py:4162 +msgid "" +"L'échelle 2 pour le mode MulScale de Tapioca est invalide, une valeur par " +"défaut, %s, est affectée." +msgstr "" +"Scale 2 from Tapioca's MulScale is invalid, a default value, %s, is affected." + +#: aperodedenis.py:4166 +msgid "L'échelle 2 pour le mode MulScale de Tapioca est trop petite :" +msgstr "Scale 2 for Tapioca's MulScale mode too small:" + +#: aperodedenis.py:4174 +msgid "L'échelle 2 de MulScale pour tapioca" +msgstr "Scale 2 of Tapioca's MulScale " + +#: aperodedenis.py:4174 +msgid "plus petite que l'échelle 1 :" +msgstr "is smaller than scale 1:" + +#: aperodedenis.py:4186 +msgid "" +"L'échelle pour le mode Line de tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "Scale for Tapioca's line invalid. A default value, %s, is affected." + +#: aperodedenis.py:4190 +msgid "Echelle pour le mode Line de tapioca trop petite : " +msgstr "Scale for Taopioca's Line mod too small:" + +#: aperodedenis.py:4202 +msgid "La valeur de delta pour le mode Line de Tapioca est invalide," +msgstr "Delta value from Tapioca's Line is invalid," + +#: aperodedenis.py:4202 +msgid "une valeur par défaut, %s, est affectée." +msgstr "a default value, %s, is affected." + +#: aperodedenis.py:4206 +msgid "Delta trop petit :" +msgstr "Delta too small:" + +#: aperodedenis.py:4206 +msgid "Minimum = 1" +msgstr "Minimum = 1" + +#: aperodedenis.py:4213 +msgid "Le zoom final pour MALT n'est pas 1,2,4 ou 8 : %s" +msgstr "Final zoom for Malt isn't 1, 2, 4 or 8: %s" + +#: aperodedenis.py:4227 +msgid "" +"Le nombre de photos utiles autour de l'image maîtresse est trop petit : %s" +msgstr "Number of useful pictures around the master picture is too small: %s" + +#: aperodedenis.py:4227 aperodedenis.py:4229 +msgid "Malt mode Geomimage :" +msgstr "Malt mode GeomImage:" + +#: aperodedenis.py:4229 +msgid "Il est mis à 5." +msgstr "It is set to 5." + +#: aperodedenis.py:4229 +msgid "" +"Le nombre de photos utiles autour de l'image centrale n'est pas numérique : " +msgstr "Number of useful pictures around central picture is not numerical." + +#: aperodedenis.py:4237 +msgid "La photo %s n'existe plus." +msgstr "The picture named %s does not exist." + +#: aperodedenis.py:4242 +msgid "Inutile et ralenti le traitement. Modifier." +msgstr "Useless and slow the process. Edit." + +#: aperodedenis.py:4246 +msgid ", est plus grande que la dimension maxi de la photo : " +msgstr ", is bigger than the maximum dimension of the picture:" + +#: aperodedenis.py:4246 +msgid "L'échelle pour le mode All de tapioca = " +msgstr "Scale for the Tapioca's All mode = " + +#: aperodedenis.py:4250 +msgid "L'échelle 2 pour le mode MulScale de tapioca= " +msgstr "Scale 2 for the Tapioca's MulScale mode = " + +#: aperodedenis.py:4250 aperodedenis.py:4254 +msgid "est plus grande que la dimension maxi de la photo :" +msgstr "is bigger than the maximum dimension of the picture:" + +#: aperodedenis.py:4254 +msgid "L'échelle pour le mode Line de tapioca = " +msgstr "Scale for Tapioca's Line mode = " + +#: aperodedenis.py:4289 aperodedenis.py:4430 aperodedenis.py:4463 +#: aperodedenis.py:4794 aperodedenis.py:4878 aperodedenis.py:4920 +#: aperodedenis.py:4961 aperodedenis.py:4992 aperodedenis.py:5023 +msgid "Choisir d'abord les photos du chantier." +msgstr "Choose the pictures of the project first." + +#: aperodedenis.py:4293 +msgid "Pour calibrer l'appareil photo" +msgstr "To calibrate the camera" + +#: aperodedenis.py:4294 +msgid "Quelques photos, convergentes, d'angles écartés" +msgstr "Some pictures, convergent, apart from angles" + +#: aperodedenis.py:4294 +msgid "en jaune la calibration actuelle" +msgstr "in yellow, the current calibration." + +#: aperodedenis.py:4295 +msgid "Supprimer" +msgstr "Delete" + +#: aperodedenis.py:4298 +msgid "Pas de photos de calibration intrinseque." +msgstr "No instrinsic calibrated pictures." + +#: aperodedenis.py:4302 +msgid "Choix inchangé." +msgstr "Unchanged choice." + +#: aperodedenis.py:4338 +msgid "Image maitresse avec masque" +msgstr "Master picture with mask" + +#: aperodedenis.py:4353 +msgid "Choisir une ou plusieurs image(s) maîtresse(s)" +msgstr "Select one or several master pictures. " + +#: aperodedenis.py:4353 +msgid "Une info bulle informe de la présence d'un masque" +msgstr "A tooltip informs of the presence of a mask. " + +#: aperodedenis.py:4353 +msgid "en jaune : les maitresses actuelles" +msgstr "Current master pictures are in yellow." + +#: aperodedenis.py:4354 +msgid "Supprimer les images maîtresses" +msgstr "Delete master pictures" + +#: aperodedenis.py:4365 +msgid "Abandon. Choix inchangé." +msgstr "Aborting. Choices unchanged." + +#: aperodedenis.py:4384 +msgid "Image maitresse obligatoire pour GeomImage." +msgstr "A master picture is needed for GeomImage" + +#: aperodedenis.py:4386 +msgid "Exécuter Tapioca/Tapas pour saisir des masques avec cette option." +msgstr "Run Tapioca / Tapas to enter masks with this option." + +#: aperodedenis.py:4392 aperodedenis.py:4395 +msgid "image maîtresse = " +msgstr "Master picture =" + +#: aperodedenis.py:4409 aperodedenis.py:4410 +msgid "un seul masque : " +msgstr "Only one mask:" + +#: aperodedenis.py:4417 +msgid "Pas de mosaique Tarama : pas de masque." +msgstr "No Tarama's mosaic. No mask." + +#: aperodedenis.py:4420 +msgid "Tracer un nouveau masque sur la mosaique Tarama" +msgstr "Plot a new mask on the mosaic Tarama" + +#: aperodedenis.py:4423 +msgid "Tracer un masque sur la mosaique Tarama" +msgstr "Plot a mask on the mosaic Tarama" + +#: aperodedenis.py:4426 +msgid "erreur dans miseAJour701_703 : " +msgstr "error in setting miseAJour701_703 : " + +#: aperodedenis.py:4435 aperodedenis.py:4502 +msgid "Il faut au moins une image maîtresse pour définir un masque." +msgstr "You need at least one master picture to define a mask." + +#: aperodedenis.py:4442 aperodedenis.py:4478 +msgid "Un masque existe déjà" +msgstr "There's already a mask" + +#: aperodedenis.py:4444 aperodedenis.py:4480 aperodedenis.py:4512 +msgid "Choisir l'image pour le masque" +msgstr "Choose a picture for the mask." + +#: aperodedenis.py:4445 aperodedenis.py:4481 +msgid "" +"Choisir une image maîtresse pour le masque\n" +"en jaune = un masque existe" +msgstr "" +"Choose a master picture for the mask.\n" +"Yellow one already have one." + +#: aperodedenis.py:4466 +msgid "Exécuter d'abord Tapioca/Tapas." +msgstr "First run Tapioca / Tapas." + +#: aperodedenis.py:4470 +msgid "Pas d'image maîtresse. Bizarre." +msgstr "No master image. Bizarre." + +#: aperodedenis.py:4513 +msgid "Choisir une image maîtresse pour le masque" +msgstr "Choose a master picture for the mask." + +#: aperodedenis.py:4531 +msgid "pas de masque" +msgstr "no mask" + +#: aperodedenis.py:4533 +msgid "Il faut une image maîtresse pour définir un masque." +msgstr "You need a master picture to define a mask." + +#: aperodedenis.py:4590 +msgid "Abandon : pas de masque créé." +msgstr "Aborting: no mask created." + +#: aperodedenis.py:4597 +msgid "Masque 3D supprimé." +msgstr "3D mask deleted." + +#: aperodedenis.py:4617 +msgid "3 points minimum, chaque point doit être placé sur au moins 2 photos" +msgstr "" +"At least three points, each point must be placed on at least two pictures." + +#: aperodedenis.py:4618 +msgid "La calibration par points GPS se fait aprés Tapas et avant Malt." +msgstr "Calibration by GPS points must be done after Tapas and before Malt." + +#: aperodedenis.py:4619 +msgid "Elle est prioritaire sur la calibration par axe, plan et métrique." +msgstr "It has priority over axis, plane and metric calibration." + +#: aperodedenis.py:4631 +msgid "Incertitude" +msgstr "Std deviations" + +#: aperodedenis.py:4636 +msgid "Ajouter un point" +msgstr "Add a point" + +#: aperodedenis.py:4637 +msgid "Supprimer des points" +msgstr "Delete points" + +#: aperodedenis.py:4638 +msgid "Placer les points" +msgstr "Place points" + +#: aperodedenis.py:4639 +msgid "Appliquer au " +msgstr "Apply on" + +#: aperodedenis.py:4639 +msgid "nuage non densifié" +msgstr "undensified point cloud" + +#: aperodedenis.py:4695 +msgid "(ou si impossible : supprimer un point)" +msgstr "(or if impossible: remove a point)" + +#: aperodedenis.py:4695 +msgid "Agrandissez la fenêtre avant d'ajouter un point GPS !" +msgstr "Extend the window before adding a GPS point !" + +#: aperodedenis.py:4699 +msgid "Soyez raisonnable : pas plus de 30 points GPS !" +msgstr "Be rational: no more than 30 GPS points !" + +#: aperodedenis.py:4712 +msgid "Aucun point à supprimer !" +msgstr "No points to delete!" + +#: aperodedenis.py:4720 +msgid "Points à supprimer" +msgstr "Points to delete" + +#: aperodedenis.py:4722 aperodedenis.py:7463 +msgid "Multiselection possible." +msgstr "Multi selection available." + +#: aperodedenis.py:4724 aperodedenis.py:7464 aperodedenis.py:7473 +#: aperodedenis.py:7479 aperodedenis.py:8295 aperodedenis.py:9181 +msgid "Annuler" +msgstr "Abort" + +#: aperodedenis.py:4806 +msgid "Choisir une photo pour placer les points GPS : " +msgstr "Choose a picture to place GPS points:" + +#: aperodedenis.py:4834 +msgid "Attention : des points portent le même nom : corriger !" +msgstr "Warning : several points have the same name : please correct it !" + +#: aperodedenis.py:4836 +msgid "Attention : un point n'a pas de nom. " +msgstr "Warning: a point does not have a name." + +#: aperodedenis.py:4838 +msgid "controle points : " +msgstr "Control points:" + +#: aperodedenis.py:4849 +msgid "Lancer d'abord tapioca/tapas" +msgstr "Launch Tapioca/Tapas first" + +#: aperodedenis.py:4849 +msgid "pour obtenir un nuage non densifié." +msgstr "to obtain a undensified point cloud." + +#: aperodedenis.py:4856 aperodedenis.py:4860 +msgid "Points GPS non conformes :" +msgstr "Improper GPS points: " + +#: aperodedenis.py:4863 +msgid "Patienter :" +msgstr "Please wait:" + +#: aperodedenis.py:4863 +msgid "le nuage est en cours de calibration" +msgstr "The point cloud is being calibrated." + +#: aperodedenis.py:4880 +msgid "Extrémité Ox" +msgstr "Ox end" + +#: aperodedenis.py:4880 +msgid "Origine Ox" +msgstr "Ox start" + +#: aperodedenis.py:4887 +msgid "Placer une ligne horizontale sur une seule photo : " +msgstr "Draw an horizontal line on a single picture:" + +#: aperodedenis.py:4912 +msgid "il faut placer les 2 points." +msgstr "You must place two points." + +#: aperodedenis.py:4928 +msgid "Placer une ligne verticale sur une seule photo : : " +msgstr "Draw a vertical line on a single picture:" + +#: aperodedenis.py:4939 +msgid "Extrémité Oy" +msgstr "Oy end" + +#: aperodedenis.py:4939 +msgid "Origine Oy" +msgstr "Oy start" + +#: aperodedenis.py:4953 +msgid "il faut placer exactement 2 points." +msgstr "You must place two points." + +#: aperodedenis.py:4965 aperodedenis.py:4996 +msgid "Plan vertical" +msgstr "Vertical plane" + +#: aperodedenis.py:4967 aperodedenis.py:4998 +msgid "Plan horizontal" +msgstr "Horizontal plane" + +#: aperodedenis.py:4970 +msgid "Une photo pour placer le plan vertical : " +msgstr "A picture to draw the vertical plane." + +#: aperodedenis.py:4988 +msgid "Délimiter un plan vertical" +msgstr "Determine a vertical plane." + +#: aperodedenis.py:5001 +msgid "Une photo pour placer le plan horizontal : " +msgstr "A picture to place the horizontal plane:" + +#: aperodedenis.py:5019 +msgid "Délimiter un plan horizontal" +msgstr "Delimit an horizontal plane" + +#: aperodedenis.py:5029 +msgid "Choisir deux fois une photo pour placer les 2 points : " +msgstr "Chose two times a picture to place both points:" + +#: aperodedenis.py:5045 +msgid "" +"Il y a dèjà 2 images avec des points 'distance'. Supprimer les points sur " +"une des 2 images." +msgstr "" +"Two pictures already have the \"distance\" points. Please remove points from " +"one of the two pictures." + +#: aperodedenis.py:5062 +msgid "Le chantier %(chant)s est terminé après %(densif)s" +msgstr "Project %(chant)s has ended after %(densif)s" + +#: aperodedenis.py:5063 +msgid "Vous pouvez modifier les options puis relancer MicMac." +msgstr "You can edit options and then relaunch MicMac." + +#: aperodedenis.py:5082 +msgid "Options incorrectes : corriger" +msgstr "Wrong options: please correct it." + +#: aperodedenis.py:5088 +msgid "Avec 2 photos MicMac construira difficilement un nuage de point dense." +msgstr "" +"With two pictures, MicMac will build a densified point cloud with difficulty." + +#: aperodedenis.py:5088 +msgid "Utiliser l'échelle -1 dans Tapioca pour obtenir un nuage optimal." +msgstr "Use scale -1 in Tapioca to obtain an optimal cloud." + +#: aperodedenis.py:5089 +msgid "Avertissement : 2 photos seulement" +msgstr "Warning: only two pictures" + +#: aperodedenis.py:5091 aperodedenis.py:5117 aperodedenis.py:5128 +#: aperodedenis.py:5139 +msgid "Continuer" +msgstr "Continue" + +#: aperodedenis.py:5109 +msgid "" +"Controle des photos en cours....\n" +"Patienter jusqu'à la fin du controle." +msgstr "" +"Pictures control... \n" +"Please wait until the end." + +#: aperodedenis.py:5114 +msgid "Les dimensions des photos ne sont pas toutes identiques." +msgstr "The dimensions of the pictures are not all the same." + +#: aperodedenis.py:5115 +msgid "Le traitement par MicMac est incertain." +msgstr "MicMac processing is uncertain." + +#: aperodedenis.py:5117 aperodedenis.py:5139 +msgid "Avertissement" +msgstr "Warning" + +#: aperodedenis.py:5124 +msgid "Absence de focales" +msgstr "Focal length not found." + +#: aperodedenis.py:5125 +msgid "Certaines photos n'ont pas de focales." +msgstr "Some pictures does not have focal length." + +#: aperodedenis.py:5126 +msgid "Le traitement echouera probablement." +msgstr "Processing will probably fail." + +#: aperodedenis.py:5127 +msgid "Mettre à jour les exifs (menu Outils)" +msgstr "Update exifs (Tools menu)" + +#: aperodedenis.py:5136 +msgid "Les focales des photos ne sont pas toutes identiques." +msgstr "Pictures focal length are not all the same." + +#: aperodedenis.py:5137 +msgid "" +"Le traitement par MicMac est possible en utilisant une focale pour la " +"calibration intrinsèque de Tapas." +msgstr "" +"MicMac processing is likely by using a focal length for Tapas intrinsic " +"calibration." + +#: aperodedenis.py:5138 +msgid "Cependant vous pouvez essayer sans cela." +msgstr "However you can try without it." + +#: aperodedenis.py:5145 +msgid "Pas assez de photos pour le traitement : il en faut au moins 2." +msgstr "No enought pictures to process: you need at least 2." + +#: aperodedenis.py:5152 +msgid "Le chantier %s a été interrompu en cours d'exécution." +msgstr "Project %s has ben interrupted because of an execution." + +#: aperodedenis.py:5153 +msgid "Le chantier est interrompu." +msgstr "Project interrupted. " + +#: aperodedenis.py:5153 +msgid "Vous pouvez le débloquer," +msgstr "You can unblock it, " + +#: aperodedenis.py:5154 +msgid "ce qui permettra de modifier les options et de le relancer." +msgstr "which will allow to edit options and relaunch it." + +#: aperodedenis.py:5155 +msgid "Débloquer le chantier" +msgstr "Unblock project" + +#: aperodedenis.py:5161 aperodedenis.py:5188 +msgid "Chantier %s de nouveau modifiable, paramètrable et exécutable." +msgstr "Project %s is editable, configurable and executable anew." + +#: aperodedenis.py:5169 +msgid "Continuer le chantier %s après tapas ?" +msgstr "Continue the project %s after Tapas?" + +#: aperodedenis.py:5170 +msgid "Le chantier est arrêté après tapas. Vous pouvez :" +msgstr "The project is stopped after Tapas. You could:" + +#: aperodedenis.py:5171 +msgid " - lancer Malt, ou C3DC, pour obtenir un nuage dense" +msgstr " - Launch Malt or C3DC to create a dense point cloud" + +#: aperodedenis.py:5172 +msgid " - débloquer le chantier pour modifier les paramètres de Tapioca/tapas" +msgstr " - Unblock the project to change Tapioca/Tapas settings" + +#: aperodedenis.py:5173 +msgid " - ne rien faire" +msgstr " - Do nothibg" + +#: aperodedenis.py:5174 +msgid "Lancer " +msgstr "Launch" + +#: aperodedenis.py:5175 +msgid "Débloquer le chantier - garder les résultats" +msgstr "Unblock project - keep the results." + +#: aperodedenis.py:5178 +msgid "abandon de Malt" +msgstr "Aborting Malt..." + +#: aperodedenis.py:5182 +msgid "" +" Reprise du chantier %s arrêté aprés TAPAS - La trace depuis l'origine sera " +"disponible dans le menu édition." +msgstr "" +"Restarting project %s stopped after TAPAS - Log available in the Edit menu." + +#: aperodedenis.py:5251 aperodedenis.py:5260 +msgid "Pourquoi MicMac s'arrête : " +msgstr "Why is MicMac stopping: " + +#: aperodedenis.py:5260 +msgid "Aucun point en correspondance sur 2 images n'a été trouvé par Tapioca." +msgstr "No corresponding points on two pictures were found by Tapioca." + +#: aperodedenis.py:5261 +msgid "Parmi les raisons de cet échec il peut y avoir :" +msgstr "Among the causes of this failure, there can be:" + +#: aperodedenis.py:5262 +msgid "" +"soit l'exif des photos ne comporte pas la focale ou plusieurs focales sont " +"présentes" +msgstr "" +"Whether the exif of the pictures does not include focal length or include " +"several focal length" + +#: aperodedenis.py:5263 +msgid "Soit l'appareil photo est inconnu de Micmac" +msgstr "Whether the camera is unknown from MicMac" + +#: aperodedenis.py:5264 +msgid "soit la qualité des photos est en cause." +msgstr "Or else, the quality of the pictures is at fault" + +#: aperodedenis.py:5265 +msgid "Utiliser les items du menu 'outils' pour vérifier ces points." +msgstr "Use items from the \"Tools\" menu to check these points." + +#: aperodedenis.py:5276 +msgid "Pas d'orientation trouvé par tapas." +msgstr "No orientation found by Tapas." + +#: aperodedenis.py:5276 +msgid "Pourquoi MicMac s'arrête :" +msgstr "Why is MicMac stopping:" + +#: aperodedenis.py:5276 +msgid "Prises de vues non positionnées." +msgstr "Shooting not placed." + +#: aperodedenis.py:5277 +msgid "Consulter l'aide (quelques conseils)," +msgstr "See Help (advices), " + +#: aperodedenis.py:5277 +msgid "consulter la trace." +msgstr "see the log." + +#: aperodedenis.py:5278 +msgid "Verifier la qualité des photos (item du menu outil)" +msgstr "Check the quality of the pictures (item from the Tool menu)" + +#: aperodedenis.py:5292 +msgid "Calibration incomplète : " +msgstr "Incomplete calibration:" + +#: aperodedenis.py:5322 +msgid ". Lancer MicMac pour reprendre le traitement." +msgstr ". Launch MicMac to resume processing." + +#: aperodedenis.py:5322 +msgid "Arrêt après Tapas " +msgstr "Stop after Tapas" + +#: aperodedenis.py:5323 +msgid "Arrêt aprés Tapas sur demande utilisateur" +msgstr "Stop after Tapas by user request" + +#: aperodedenis.py:5336 +msgid "Tapas n'a pas généré de nuage de points." +msgstr "Tapas didn't generate a point cloud" + +#: aperodedenis.py:5337 aperodedenis.py:5344 +msgid "Le traitement ne peut se poursuivre." +msgstr "The process cannot continue." + +#: aperodedenis.py:5338 +msgid "" +"Vérifier la qualité des photos, modifier les paramètres et relancer tapioca-" +"tapas" +msgstr "" +"Check the quality of the pictures, change settings and relaunch Tapioca-" +"Tapas." + +#: aperodedenis.py:5343 +msgid "Pas de masque 3D, ou d'image maîtresse pour Malt." +msgstr "No 3D mask, or master image for Malt." + +#: aperodedenis.py:5345 +msgid "Définir une image maîtresse" +msgstr "Define a master picture" + +#: aperodedenis.py:5346 +msgid "ou Changer le mode 'GeomImage' qui impose une image maîtresse" +msgstr "or change GeomImage mode which impose a master picture." + +#: aperodedenis.py:5347 +msgid "ou définir un masque 3D" +msgstr "or define a 3D mask" + +#: aperodedenis.py:5348 +msgid "Pour cela utiliser l'item option/Malt ou option/C3DC du menu MicMac" +msgstr "" +"To do so, use the item option/Malt or option/C3DC from the MicMac menu." + +#: aperodedenis.py:5367 +msgid "Le fichier modele3D.ply précédent est renommé en " +msgstr "modele3D.ply file renamed into" + +#: aperodedenis.py:5369 +msgid "erreur renommage ancien modele_3d en " +msgstr "Error renaming ancient modele_3D into" + +#: aperodedenis.py:5370 +msgid "" +"Le fichier Modele3D.ply précédent n'a pu être renommé. Il sera remplacé." +msgstr "Previous Modele3D.ply file couldn't be renamed. It will be replaced." + +#: aperodedenis.py:5389 +msgid "Fin du traitement MicMac " +msgstr "End of MicMac processing" + +#: aperodedenis.py:5400 +msgid "Tapas non effectué, lancer Micmac depuis le menu. Etat du chantier = " +msgstr "Tapas not performed, launch MicMac from the menu. Project progress = " + +#: aperodedenis.py:5406 +msgid "Pourquoi MicMac est arrêté :" +msgstr "Why is MicMac stopping:" + +#: aperodedenis.py:5407 +msgid "Pas d'image maîtresse." +msgstr "No master picture." + +#: aperodedenis.py:5408 +msgid "Celle-ci est nécessaire pour l'option choisie geomImage de Malt." +msgstr "It is required for the Malt's GeomImage choosen option." + +#: aperodedenis.py:5409 +msgid "" +"Pour corriger modifier les options de Malt ou choississez un masque 3D avec " +"C3DC." +msgstr "Please edit Malt options or choose a 3D mask with C3DC" + +#: aperodedenis.py:5410 +msgid "Corriger." +msgstr "Correct." + +#: aperodedenis.py:5425 +msgid "Erreur copie modele3D.ply" +msgstr "Error copying modele3D.ply" + +#: aperodedenis.py:5446 +msgid "erreur malt GeomImage copy de nuage en modele3D : " +msgstr "Error Malt GeomImage copy of point cloud in modele3D: " + +#: aperodedenis.py:5446 aperodedenis.py:5449 aperodedenis.py:5468 +#: aperodedenis.py:5471 +msgid " pour : " +msgstr " for:" + +#: aperodedenis.py:5449 +msgid "erreur malt GeomImage fusion des nuages en modele3D : " +msgstr "error Malt GeomImage merging point cloud in modele 3D" + +#: aperodedenis.py:5468 +msgid "erreur malt AperoDeDenis copy de nuage en modele3D : " +msgstr "Malt error AperoDeDenis copy of cloud in model3D:" + +#: aperodedenis.py:5471 +msgid "erreur malt AperoDeDenis fusion des nuages en modele3D : " +msgstr "Error malt AperoDeDenis cloud merging in 3D model:" + +#: aperodedenis.py:5484 +msgid "Aucune photo choisie. Abandon." +msgstr "No choosent picture. Aborting." + +#: aperodedenis.py:5488 +msgid "Une seule photo choisie. Abandon." +msgstr "Only one choosen picture. Aborted." + +#: aperodedenis.py:5494 +msgid "TRACE DETAILLEE" +msgstr "DETAILED LOG" + +#: aperodedenis.py:5495 +msgid "TRACE SYNTHETIQUE" +msgstr "SYNTHETHIC LOG" + +#: aperodedenis.py:5497 +msgid "DEBUT DU TRAITEMENT MICMAC à " +msgstr "START OF MICMAC PROCESSING at" + +#: aperodedenis.py:5500 +msgid "Photos choisies :" +msgstr "Choosen pictures:" + +#: aperodedenis.py:5501 +msgid "Ces photos sont recopiées dans le répertoire du chantier :" +msgstr "Those pictures are copied in the project directory:" + +#: aperodedenis.py:5557 aperodedenis.py:5563 +msgid "" +"Recherche des points remarquables et des correspondances sur une image de " +"taille %s pixels." +msgstr "" +"Searching for tie-points and correspondences on a picture of %s pixels." + +#: aperodedenis.py:5561 +msgid "" +"Recherche des points remarquables et des correspondances sur l'image entière." +msgstr "" +"Searching for remarkable points and correspodences on the whole picture." + +#: aperodedenis.py:5574 +msgid "Une seule photo pour la calibration intrinsèque : insuffisant." +msgstr "Only one picture for intrinsic calibration: insufficient." + +#: aperodedenis.py:5578 +msgid "Calibration intrinsèque lancée sur les photos : " +msgstr "Intrinsic calibration launche on pictures:" + +#: aperodedenis.py:5592 +msgid "" +"Calibration intrinsèque, pour trouver les réglages de l'appareil photo sur " +"quelques photos" +msgstr "Intrinsic calibration, to find camera settings on some pictures." + +#: aperodedenis.py:5592 +msgid "Recherche d'un point de convergence au centre de l'image." +msgstr "Searching for a convergence points in the picture center." + +#: aperodedenis.py:5598 +msgid "La calibration intrinsèque n'a pas permis de trouver une orientation." +msgstr "The intrinsic calibration couldn't find an orientation." + +#: aperodedenis.py:5601 +msgid "Calibration intrinsèque effectuée." +msgstr "Intrinsic calibration done." + +#: aperodedenis.py:5605 +msgid "" +"Une seule photo pour Tapas sans les photos de calibration : insuffisant." +msgstr "Only one picture for Tapas without calibration pictures: insufficient." + +#: aperodedenis.py:5634 +msgid "Recherche l'orientation des prises de vues" +msgstr "Searching for shooting orientation" + +#: aperodedenis.py:5646 +msgid "Calibration, pour trouver les réglages intrinsèques de l'appareil photo" +msgstr "Calibration, to find intrinsic settings of the camera" + +#: aperodedenis.py:5646 +msgid "Recherche l'orientation des prises de vue." +msgstr "Searching for shooting orientation." + +#: aperodedenis.py:5663 +msgid "" +"Fixe l'orientation (axe,plan et métrique) suivant les options de " +"'calibration'" +msgstr "" +"Set orientation (axis, plane and metric) following calibration options." + +#: aperodedenis.py:5682 +msgid "Création d'un nuage de points grossier." +msgstr "Creating rough point cloud." + +#: aperodedenis.py:5682 +msgid "Positionne les appareils photos autour du sujet." +msgstr "Set cameras around the subject." + +#: aperodedenis.py:5688 +msgid "ligne avec meta : " +msgstr "Line with meta:" + +#: aperodedenis.py:5689 +msgid "" +"ATTENTION : des metadonnées nécessaires sont absentes des photos. Vérifier " +"l'exif." +msgstr "" +"Warning : some required metadatas not found in the pictures. Check the exif." + +#: aperodedenis.py:5700 +msgid "Ouverture du nuage de points après Apericloud" +msgstr "Opening point cloud after AperiCloud" + +#: aperodedenis.py:5703 +msgid "Pas de fichier AperiCloud.ply généré." +msgstr "No AperiCloud.ply file generated." + +#: aperodedenis.py:5705 +msgid "" +"Consulter l'aide (quelques conseils),\n" +"Consulter la trace." +msgstr "" +"See Help (Advices),\n" +"See the log." + +#: aperodedenis.py:5711 +msgid "Tarama : mosaïque des photos d'aprés les tie points" +msgstr "Tarama: mosaic of the photos after the tie points" + +#: aperodedenis.py:5722 +msgid "" +"Prise en compte des points GPS : nécessite au minimum 3 points, chacun sur 2 " +"photos" +msgstr "" +"Consideration GPS points: there must be a minimum of three points, each " +"point on at least two pictures" + +#: aperodedenis.py:5724 +msgid "" +"Le nombre minimum de points placés sur les photos n'est pas atteint. Abandon." +msgstr "Minimum number of points on pictures not reached. Aborting." + +#: aperodedenis.py:5749 +msgid "Préparation du lancement de Malt" +msgstr "Preparing Malt's launch." + +#: aperodedenis.py:5758 +msgid "Photos utiles pour malt GeomImage : " +msgstr "Photos useful for malt GeomImage:" + +#: aperodedenis.py:5760 +msgid "Malt sur toutes les photos" +msgstr "Malt on all photos" + +#: aperodedenis.py:5772 +msgid "Photos utiles pour malt AperoDeDenis : " +msgstr "Useful photos for malt AperoDeDenis:" + +#: aperodedenis.py:5783 +msgid "Mosaique et masque: " +msgstr "Mosaic and mask:" + +#: aperodedenis.py:5785 +msgid "Mosaique seule : " +msgstr "Mosaic alone:" + +#: aperodedenis.py:5806 aperodedenis.py:5963 aperodedenis.py:8082 +msgid "ATTENTION : cette procédure est longue : patience !" +msgstr "Warning: this process can be long." + +#: aperodedenis.py:5937 +msgid "lance Tawny" +msgstr "Launch Tawny" + +#: aperodedenis.py:5943 +msgid " : voir la trace complète." +msgstr " : see complete log." + +#: aperodedenis.py:6065 +msgid "Echec du traitement MICMAC" +msgstr "MicMac process failed. " + +#: aperodedenis.py:6065 +msgid "Pas de fichier %s généré." +msgstr "No %s file generated." + +#: aperodedenis.py:6073 +msgid "Nuage de points %s généré." +msgstr "Point cloud %s generated." + +#: aperodedenis.py:6099 +msgid "Détermine un indice de qualité des photos en mode 'line'" +msgstr "Set a quality level on pictures in 'line' mode" + +#: aperodedenis.py:6100 aperodedenis.py:6131 +msgid "Le résultat sera inscrit dans le fichier trace synthétique" +msgstr "The result will be written in the synthetic log file. " + +#: aperodedenis.py:6100 aperodedenis.py:6131 aperodedenis.py:6207 +msgid "Patience..." +msgstr "Please wait..." + +#: aperodedenis.py:6102 +msgid "Debut de la recherche sur la qualité des photos mode 'Line'." +msgstr "Starting search on quality of the pictures in 'Line' mode." + +#: aperodedenis.py:6130 +msgid "Détermine un indice de qualité des photos en mode 'All' ou 'MulScale'" +msgstr "Set a quality level on pictures in 'All' or 'MulScale' mode" + +#: aperodedenis.py:6133 +msgid "" +"Debut de la recherche sur la qualité des photos, mode 'All' ou 'MulScale'." +msgstr "" +"Starting search on the quality of the pictures in 'All' or 'MulScale' mode." + +#: aperodedenis.py:6181 aperodedenis.py:8422 +msgid "Classement des photos par nombre de points homologues :" +msgstr "Pictures ranking by number of tie-points:" + +#: aperodedenis.py:6183 +msgid " score = " +msgstr " score =" + +#: aperodedenis.py:6183 +msgid "photo " +msgstr "picture" + +#: aperodedenis.py:6186 aperodedenis.py:8429 +msgid "Aucune photo n'a de point analogue avec une autre." +msgstr "No analagous points found between any pictures." + +#: aperodedenis.py:6190 +msgid "Qualité des photos suite au traitement : " +msgstr "Quality of the pictures after processing:" + +#: aperodedenis.py:6191 aperodedenis.py:8344 aperodedenis.py:8349 +#: aperodedenis.py:8357 +msgid "Homol" +msgstr "Homol" + +#: aperodedenis.py:6203 +msgid "Fin d'examen de qualité des photos." +msgstr "End of quality pictures examination." + +#: aperodedenis.py:6207 +msgid "Copie des photos dans un répertoire de test." +msgstr "Copying pictures in a test directory." + +#: aperodedenis.py:6232 +msgid "Créer un nouveau chantier avec les photos : " +msgstr "Create a new project with this pictures :" + +#: aperodedenis.py:6233 +msgid "Les paramètres de Tapioca/Malt seront optimisés." +msgstr "The parameters of Tapioca and Malt will be optimized." + +#: aperodedenis.py:6324 +msgid "Caractéristiques de l'appareil photo : " +msgstr "Camera characteristics:" + +#: aperodedenis.py:6327 +msgid "fabricant : " +msgstr "Manufacturer:" + +#: aperodedenis.py:6331 +msgid "Nom de l'appareil photo inacessible." +msgstr "Camera name unreachable." + +#: aperodedenis.py:6333 +msgid "Nom de l'appareil photo : " +msgstr "Camera name:" + +#: aperodedenis.py:6339 +msgid "Pas de focale dans l'exif." +msgstr "No focal length in exif:" + +#: aperodedenis.py:6341 +msgid "Focale : " +msgstr "Focal length:" + +#: aperodedenis.py:6344 +msgid "Pas de focale équivalente 35 mm dans l'exif :" +msgstr "No equivalent focal length 35mm in the exif:" + +#: aperodedenis.py:6344 +msgid "Présence de la taille du capteur dans DicoCamera nécesssaire." +msgstr "The size of the sensor is required in DicoCamera." + +#: aperodedenis.py:6347 +msgid "Focale équivalente 35 mm absente de l'exif" +msgstr "No equivalent focal length 35mm in the exif:" + +#: aperodedenis.py:6349 +msgid "Focale équivalente 35 mm : " +msgstr "Equivalent focal length 35mm" + +#: aperodedenis.py:6352 aperodedenis.py:6453 +msgid "" +"DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin." +msgstr "DicoCamera.xml not found: please link the MicMac\\bin path." + +#: aperodedenis.py:6356 +msgid "L'appareil est inconnu dans DicoCamera.XML." +msgstr "The camera is not known by DicoCamera.xml" + +#: aperodedenis.py:6358 +msgid "L'appareil est connu dans DicoCamera.XML." +msgstr "The camera is known by DicoCamera.xml" + +#: aperodedenis.py:6359 +msgid "Taille du capteur en mm : " +msgstr "Sensor size in mm:" + +#: aperodedenis.py:6365 +msgid "Appareil photo :" +msgstr "Camera:" + +#: aperodedenis.py:6387 +msgid "Erreur dans exiftool : " +msgstr "Exiftool error:" + +#: aperodedenis.py:6389 +msgid "erreur tagExif : " +msgstr "TagExif error:" + +#: aperodedenis.py:6450 +msgid "Pas trouvé de nom d'appareil photo dans l'exif." +msgstr "The name of the camera was not found in the exif." + +#: aperodedenis.py:6456 +msgid "" +"Le fichier DicoCamera.xml contient la taille du capteur pour l'appareil :" +msgstr "The file DicoCamera.xml contains the size of the sensors:" + +#: aperodedenis.py:6457 +msgid "taille = " +msgstr "size =" + +#: aperodedenis.py:6458 +msgid "Modification non prévue dans cette version de l'outil AperoDeDenis" +msgstr "No changements planned in the current version of AperoDeDenis" + +#: aperodedenis.py:6462 +msgid "Pour l'appareil " +msgstr "For the camera" + +#: aperodedenis.py:6467 +msgid "Paramètrer au préalable le chemin de MicMac\\bin." +msgstr "Please set MicMac\\bin path beforehand." + +#: aperodedenis.py:6471 +msgid "NomCourt" +msgstr "ShortName" + +#: aperodedenis.py:6473 +msgid "tailleEnMM" +msgstr "SizeInMM" + +#: aperodedenis.py:6488 +msgid "Erreur lors de l'écriture de DicoCamera.xml" +msgstr "Error writing in DicoCamera.xml" + +#: aperodedenis.py:6488 +msgid "Une sauvegarde a été créée : DicoCamerra.xml.sav" +msgstr "Save have been created: DicoCamera.xml.sav" + +#: aperodedenis.py:6491 aperodedenis.py:6498 +msgid "Dimensions du capteur non mis à jour" +msgstr "The dimensions of the sensors were not updated." + +#: aperodedenis.py:6494 +msgid "Dimensions du capteur mis à jour" +msgstr "The dimensions of the sensors were updated." + +#: aperodedenis.py:6508 +msgid "Toutes les focales : " +msgstr "All focal length:" + +#: aperodedenis.py:6517 +msgid "Saisir une ou plusieurs ligne(s) de commande" +msgstr "Enter one or more command line (s)" + +#: aperodedenis.py:6519 +msgid "Attention : Le chantier n'existe pas." +msgstr "Warning : no project." + +#: aperodedenis.py:6522 +msgid "" +"Entrer soit une commande MicMac, par exemple : mm3d GCPBascule .*.JPG " +"Arbitrary" +msgstr "" +"Enter either a MicMac command, for example: mm3d GCPBascule. * .JPG Arbitrary" + +#: aperodedenis.py:6523 +msgid "S'il n'y a pas de path sur mm3d entrer le chemin : " +msgstr "If there is no path on mm3d enter the path:" + +#: aperodedenis.py:6524 +msgid "" +"soit une commande du système, par exemple sous windows : del /S /Q Tmp-MM-Dir" +msgstr "" +"Either a system command, for example under windows: del / S / Q Tmp-MM-Dir" + +#: aperodedenis.py:6525 +msgid "Sous votre responsabilité" +msgstr "Under your responsibility" + +#: aperodedenis.py:6540 +msgid "Choisir le chantier pour ajouter les points gps." +msgstr "Choose the project to add the gps points." + +#: aperodedenis.py:6562 +msgid "Erreur restauration points GPS : " +msgstr "Error restoring GPS points:" + +#: aperodedenis.py:6612 +msgid "Interface graphique pour lancer les modules de MICMAC." +msgstr "Graphical User Interface to launch MICMAC modules." + +#: aperodedenis.py:6613 +msgid "Utilisable sous Linux, Windows, Mac OS." +msgstr "Available on Linux, Windows and Mac OS." + +#: aperodedenis.py:6614 +msgid "Logiciel libre diffusé sous licence CeCILL-B." +msgstr "A free software licensed CeCILL-B." + +#: aperodedenis.py:6616 +msgid "" +"La barre de titre présente le nom du chantier et la version de l'outil. Une " +"* indique que le chantier est à sauvegarder." +msgstr "" +"The title bar shows the current project's name and AperoDeDenis current " +"version. A * in the title bar means that the project has been modified and " +"should be saved." + +#: aperodedenis.py:6617 +msgid "Menu Fichier :" +msgstr "File menu:" + +#: aperodedenis.py:6618 +msgid "" +" - Nouveau chantier : constitution d'un 'chantier' comportant les " +"photos, les options d'exécution de Micmac et" +msgstr "" +" - New project: create a new project with pictures, MicMac execution " +"options and" + +#: aperodedenis.py:6619 +msgid " les résultats des traitements." +msgstr " processing results." + +#: aperodedenis.py:6620 +msgid " Les paramètres du chantier sont conservés dans le fichier " +msgstr " Project's settings are saved in the file" + +#: aperodedenis.py:6621 +msgid "" +" Enregistrer le chantier crée une arborescence dont la racine est le " +"répertoire des photos et le nom du chantier." +msgstr "" +" Save the project and create a tree whose root is the pictures " +"directory and the project's name." + +#: aperodedenis.py:6622 +msgid "" +" - Ouvrir un chantier : revenir sur un ancien chantier pour le " +"poursuivre ou consulter les résultats." +msgstr "" +" - Open project: open an ancient project to work on it or consult " +"view results." + +#: aperodedenis.py:6623 +msgid "" +" - Enregistrer le chantier : enregistre le chantier en cours sans " +"l'exécuter." +msgstr " - Save project: save current project without executing it." + +#: aperodedenis.py:6624 +msgid "" +" Une * dans la barre de titre indique que le chantier a été modifié." +msgstr "" +" A * in the title bar means that the project has been modified. " + +#: aperodedenis.py:6625 +msgid "" +" Le chantier en cours, même non enregistré, est conservé lors de la " +"fermeture de l'application." +msgstr "" +" Saved or not, the current project will be stored when closing the " +"application." + +#: aperodedenis.py:6626 +msgid " - Renommer le chantier : personnalise le nom du chantier." +msgstr " - Rename project: change project name." + +#: aperodedenis.py:6627 +msgid "" +" Le chantier est déplacé dans l'arborescence en indiquant un chemin " +"absolu ou relatif." +msgstr "" +" Project will be displaced in the tree giving an absolute or relative " +"path." + +#: aperodedenis.py:6628 +msgid "" +" Par exemple : 'D:\\MonPremierChantier' nomme 'MonPremierChantier' " +"sous la racine du disque D." +msgstr "" +" For instance: 'D:\\MyFirstProject' name 'MyFirstProject' Under D: " +"root. " + +#: aperodedenis.py:6629 +msgid "" +" Attention : le changement de disque n'est pas possible dans cette " +"version de l'outil." +msgstr " Warning: disk change is not available in this version." + +#: aperodedenis.py:6630 +msgid "" +" - Exporter le chantier en cours : création d'une archive du chantier, " +"qui permet :" +msgstr "" +" - Export current project: create a project archive, which allows:" + +#: aperodedenis.py:6631 +msgid " - de conserver le chantier en l'état, pour y revenir." +msgstr "" +" - To store the project in its current status, to work on it later" + +#: aperodedenis.py:6632 +msgid "" +" - de l'importer sous un autre répertoire, un autre disque, un " +"autre ordinateur, un autre système d'exploitation" +msgstr "" +" - to importer it in another directory, disk, computer or " +"operating system" + +#: aperodedenis.py:6633 +msgid " - Importer un chantier :" +msgstr " - Import project" + +#: aperodedenis.py:6634 +msgid "" +" - copie le chantier sauvegardé dans un nouvel environnement " +"(ordinateur, système d'exploitation)" +msgstr "" +" - Create a copy of a saved project in a new environnement " +"(computer, operating system)" + +#: aperodedenis.py:6635 +msgid "" +" - un exemple d'intérêt : copier un chantier aprés tapas, lancer " +"malt avec des options variées sans perdre l'original." +msgstr "" +" - for instance: copy a project after Tapas, launch Malt with " +"different options without loosing the original." + +#: aperodedenis.py:6636 +msgid "" +" - Du ménage ! : supprimer les chantiers : chaque chantier crée une " +"arborescence de travail." +msgstr "" +" - Let's clean ! : delete projects : each project create a work tree." + +#: aperodedenis.py:6637 +msgid " Cet item permet de supprimer les répertoires devenus inutiles." +msgstr " This item allow to delete useless directories." + +#: aperodedenis.py:6638 +msgid "" +" Aprés un message demandant confirmation la suppression est " +"définitive, sans récupération possible :" +msgstr "" +" You will be asked to confirm the suppression, then the project will " +"be deleted for good:" + +#: aperodedenis.py:6639 +msgid "" +" toute l'arborescence est supprimée, même les archives exportées." +msgstr " the entire tree will be deleted, even exported archives." + +#: aperodedenis.py:6640 +msgid "" +" - Quitter : quitte l'application, le chantier en cours est conservé " +"et sera ouvert lors de la prochaine exécution." +msgstr "" +" - Exit: exit the application, current project is stored and will be " +"opened at the next execution." + +#: aperodedenis.py:6641 +msgid "Menu Edition :" +msgstr "Edit menu:" + +#: aperodedenis.py:6642 +msgid "" +" - Afficher l'état du chantier : affiche les paramètres du chantier et " +"son état d'exécution." +msgstr "" +" - Display project progress: display project settings and his " +"execution status." + +#: aperodedenis.py:6643 +msgid "" +" Par défaut l'état du chantier est affiché lors du lancement de " +"l'application." +msgstr "" +" The project progress is displayed by default when the application " +"is launched." + +#: aperodedenis.py:6644 +msgid "" +" Cet item est utile après un message ou l'affichage d'une trace." +msgstr " This option is usefull after a message or displaying a log." + +#: aperodedenis.py:6645 +msgid "" +" - Plusieurs items permettent de consulter les photos, les traces et " +"les vues 3D du chantier en cours." +msgstr "" +" - Several options allows to see pictures, logs and 3D view of the " +"current project." + +#: aperodedenis.py:6646 +msgid "" +" Visualiser toutes les photos sélectionnées : visualise les photos" +msgstr " Display all selected pictures: display pictures" + +#: aperodedenis.py:6647 +msgid "" +" Visualiser les points GPS : visu des seules " +"photos avec points GPS." +msgstr "" +" Display GPS points: display pictures which have GPS points." + +#: aperodedenis.py:6648 +msgid "" +" Visualiser le masque 3D : visualise le masque " +"3D" +msgstr " Display 3D mask: display the 3D mask" + +#: aperodedenis.py:6649 +msgid "" +" Visualiser le masque 2D et l'image maitre : visualise le masque " +"2D s'il existe et de l'image maître." +msgstr "" +" Display 2D mask and master picture: display the 2D mask if " +"existing and the master picture." + +#: aperodedenis.py:6650 +msgid "" +" Visualiser la ligne horizontale/verticale : visualise le repère " +"Ox ou Oy." +msgstr "" +" Display horizontal/vertical line: display the Ox or Oy frame." + +#: aperodedenis.py:6651 +msgid "" +" Visualiser la zone plane : visualise la zone " +"plane" +msgstr " Display the plane area: display the plane area" + +#: aperodedenis.py:6652 +msgid "" +" Visualiser la distance : visualise de la " +"distance et les points associés." +msgstr "" +" Display the distance: display the distance and associated points." + +#: aperodedenis.py:6654 +msgid "" +" Afficher la trace complete du chantier : visualise la trace " +"complète, standard micmac" +msgstr "" +" Display project's complete log: display the complete log, micmac " +"standard." + +#: aperodedenis.py:6655 +msgid "" +" Afficher la trace synthétique du chantier : visualise la trace " +"filtrée par aperoDeDenis, moins bavarde" +msgstr "" +" Display the project's synthetic log: display the synthethic log " +"from AperoDeDenis, less talkative." + +#: aperodedenis.py:6657 +msgid "" +" Afficher l'image 3D non densifiée : lance l'outil pour " +"ouvrir les .PLY sur l'image 3D produite par Tapas" +msgstr "" +" Display the non densified 3D picture: launch the .PLY opener on " +"the 3D picture created by Tapas" + +#: aperodedenis.py:6658 +msgid "" +" Afficher l'image 3D densifiée : lance l'outil pour " +"ouvrir les .PLY sur l'image 3D produite par Malt ou C3DC" +msgstr "" +" Display the densified 3D picture: launch the .ply opener on the " +"3D picture created by Malt or C3DC" + +#: aperodedenis.py:6660 +msgid "" +" Lister Visualiser les images 3D : liste la pyramide " +"des images 3D, créées à chaque étape de Malt" +msgstr "" +" Display 3D pictures list: list the 3D pictures pyramid, created " +"by Malt at each of its steps." + +#: aperodedenis.py:6661 +msgid "" +" Fusionner des images 3D : permet de fusionner " +"plusieurs PLY en un seul" +msgstr " Merge 3D pictures: allow to merge several PLY in one file." + +#: aperodedenis.py:6662 +msgid "Menu MicMac :" +msgstr "MicMac menu:" + +#: aperodedenis.py:6663 +msgid "" +" - Choisir les photos : permet choisir les photos JPG, GIF, TIF ou BMP " +"pour le traitement." +msgstr "" +" - Select pictures: allow to select JPG, GIF, TIF or BMP pictures for " +"processing." + +#: aperodedenis.py:6664 +msgid "" +" Remarque : les photos GIF et BMP seront converties en JPG " +"(nécessite la présence de l'outil convert)." +msgstr "" +" Note: GIF and BMP pictures will be converted into JPG (convert tool " +"required)" + +#: aperodedenis.py:6665 +msgid "" +" Un EXIF avec la focale utilisée pour la prise de vue est " +"nécessaire : si besoin l'ajouter (menu Outil/ajout exif)." +msgstr "" +" An exif with the used focal length is required: add it if needed " +"(Tools/Add exif)." + +#: aperodedenis.py:6666 +msgid " Remarque : " +msgstr " Note:" + +#: aperodedenis.py:6667 +msgid "" +" Le fichier DicoCamera.xml doit comporter la taille du " +"capteur de l'appareil (voir menu Outils)" +msgstr "" +" DicoCamera.xml must include the size of the captor of " +"the camera(see Tools menu)" + +#: aperodedenis.py:6668 +msgid "" +" - Options : choisir les options des modules Tapioca, Tapas (nuage non " +"densifié) puis de Malt (nuage densifié) : " +msgstr "" +" - Options: choose options from Tapioca, Tapas (undensified point " +"cloud) and then Malt (densified point cloud) modules." + +#: aperodedenis.py:6669 +msgid "" +" Les options suivantes concernent le calcul du nuage de points NON " +"densifié :" +msgstr " Following options affect undensified point cloud:" + +#: aperodedenis.py:6670 +msgid "" +" - Tapioca : options et sous options associées (échelles, " +"fichier xml)" +msgstr "" +" - Tapioca: options and associated sub-options (scales, " +"xml files)" + +#: aperodedenis.py:6671 +msgid "" +" - Tapas : choix d'un mode de calcul, possibilité " +"d'arrêter le traitement après tapas." +msgstr "" +" - Tapas : caluclation mode choice, allow to stop " +"processing after Tapas." + +#: aperodedenis.py:6672 +msgid "" +" La calibration intrinsèque permet de lancer " +"Tapas sur un premier lot de photos." +msgstr "" +" Intrinsic calibration allows to launch Tapas " +"on a first package of pictures." + +#: aperodedenis.py:6673 +msgid "" +" Typiquement sur les photos de plus grande " +"focale si il y a 2 focales différentes." +msgstr "" +" Typically on pictures with a more large " +"focal length in case of several different focal length." + +#: aperodedenis.py:6674 +msgid "" +" L'arrêt après Tapas est nécessaire pour " +"décrire le masque 2D ou 3D." +msgstr "" +" Stop after Tapas is necessary to create 2D " +"or 3D mask." + +#: aperodedenis.py:6675 +msgid "" +" Produit une image 3D non densifiée avec " +"position des appareils photos." +msgstr "" +" Create a undensified 3D picture with cameras " +"position." + +#: aperodedenis.py:6676 +msgid "" +" - Calibration : définir un axe, une zone plane, une " +"distance pour définir le repère du chantier." +msgstr "" +" - Calibration: define an axis, a plane area, a distance " +"to define project's frame." + +#: aperodedenis.py:6677 +msgid "" +" - GPS : définir les points de calage GPS qui permettent " +"de géolocaliser la scène." +msgstr "" +" - GPS : define GPS points, which allow to geolocate the " +"scene." + +#: aperodedenis.py:6678 +msgid "" +" Pour être utilisé chaque point, minimum 3, doit " +"être placé sur au moins 2 photos." +msgstr "" +" To be used, a minimum of three points must be " +"placed on at least two pictures." + +#: aperodedenis.py:6679 +msgid "" +" Cette option est utilisée pour le nuage de point " +"non densifié ET pour le nuage densifié." +msgstr "" +" This option can be used for densified and " +"undensified point clouds." + +#: aperodedenis.py:6680 +msgid "" +" Les 3 options suivantes concernent le calcul du nuage de points " +"densifié :" +msgstr "" +" Three following options are related with densified point cloud " +"calculation:" + +#: aperodedenis.py:6681 +msgid "" +" - Malt : choix du mode et du niveau de densification." +msgstr " - Malt: densification mode and level choice." + +#: aperodedenis.py:6682 +msgid " Si le mode est GeomImage : " +msgstr " If GeomImage is the mod: " + +#: aperodedenis.py:6683 +msgid "" +" désigner une ou plusieurs images maîtresses" +msgstr "" +" select one or several master pictures" + +#: aperodedenis.py:6684 +msgid "" +" dessiner si besoin le ou les masques " +"associés." +msgstr "" +" If needed, draw the associated masks." + +#: aperodedenis.py:6685 +msgid "" +" Seuls les points visibles sur les images " +"maitres seront sur l'image 3D finale." +msgstr "" +" Only the visible points on master pictures " +"will be displayed on the final 3D picture." + +#: aperodedenis.py:6686 +msgid "" +" Le masque limite la zone utile de l'image " +"3D finale." +msgstr "" +" The mask limits the final 3D picture's useful area." + +#: aperodedenis.py:6687 +msgid "" +" La molette permet de zoomer et le clic " +"droit maintenu de déplacer l'image." +msgstr "" +" The scroll button allows to zoom and the right " +"click to move the picture." + +#: aperodedenis.py:6688 +msgid "" +" Supprimer une image maîtresse de la liste " +"réinitialise le masque." +msgstr "" +" Delete a master picture from the list will reset " +"the mask." + +#: aperodedenis.py:6689 +msgid "" +" Nombre de photos utiles autour de l'image " +"maîtresse :" +msgstr "" +" Number of useful pictures around the master picture:" + +#: aperodedenis.py:6690 +msgid "" +" Permet de limiter les recherches aux " +"images entourant chaque image maîtresse." +msgstr "" +" Allows to limite pictures searches to " +"pictures surrouding each master picture." + +#: aperodedenis.py:6691 +msgid "" +" Choix du niveau de densification final : " +"8,4,2 ou 1." +msgstr "" +" Final densification level choice: 8, 4, 2 or 1" + +#: aperodedenis.py:6692 +msgid " Le niveau 1 est le plus dense. " +msgstr " Level 1 is the densest." + +#: aperodedenis.py:6693 +msgid "" +" La géométrie est revue à chaque niveau et " +"de plus en plus précise : " +msgstr "" +" Geometry is reworked at each level and is " +"more and more precise:" + +#: aperodedenis.py:6694 +msgid "" +" la densification s'accroît, et la " +"géométrie s'affine aussi." +msgstr "" +" Densification increases, and geometry " +"refines." + +#: aperodedenis.py:6695 +msgid "" +" - C3DC : dessiner le masque 3D sur le nuage de points " +"AperiCloud généré par Tapas.." +msgstr "" +" - C3DC: draw 3D mask on AperiCloud's point cloud " +"generated by Tapas." + +#: aperodedenis.py:6696 +msgid "" +" Les touches fonctions à utiliser sont " +"décrites dans l'onglet." +msgstr " Keys to use are described in the tab." + +#: aperodedenis.py:6697 +msgid "" +" Le masque limite la zone en 3 dimensions de " +"l'image finale." +msgstr "" +" The mask limits the final picture's 3D area." + +#: aperodedenis.py:6698 +msgid " L'outil de saisie est issu de micmac." +msgstr " The entry tool is from MicMac." + +#: aperodedenis.py:6699 +msgid "" +" - GPS : définir les points de calage GPS qui " +"permettent de géolocaliser la scène." +msgstr "" +" - GPS : define GPS points, which allow to geolocate the " +"scene." + +#: aperodedenis.py:6700 +msgid "" +" Pour être utilisé chaque point, minimum 3, " +"doit être placé sur au moins 2 photos." +msgstr "" +" To be used, each point, with a minimum of 3, " +"must be placed on at least two pictures." + +#: aperodedenis.py:6701 +msgid "" +" Le bouton 'appliquer' permet de calibrer le " +"modèle non densifié immédiatement." +msgstr " The \"Apply\" button allows to " + +#: aperodedenis.py:6702 +msgid "" +" - Lancer MicMac : enregistre le chantier et lance le traitement avec " +"les options par défaut ou choisies par l'item 'options'." +msgstr "" +" - Launch MicMac : save project et launch the processing with default " +"or choosen options from the 'options' item." + +#: aperodedenis.py:6703 +msgid "" +" Relance micmac si l'arrêt a été demandé après tapas." +msgstr "" +" Relaunch MicMac if stopping was asked after Tapas." + +#: aperodedenis.py:6704 +msgid "" +" Lancer micmac bloque les photos et les options du " +"chantier." +msgstr "" +" Launch MicMac block project's pictures and options." + +#: aperodedenis.py:6705 +msgid "" +" Pour débloquer le chantier il faut lancer micmac à " +"nouveau et choisir le débloquage." +msgstr "" +" To unblock the project, you must launch MicMac anew " +"and choose to unblock." + +#: aperodedenis.py:6706 +msgid "" +" Le débloquage permet de relancer Malt sans relancer " +"tapioca/tapas : " +msgstr "" +" Unblock allows to relaunch Malt without relaunching " +"Tapioca/Tapas:" + +#: aperodedenis.py:6707 +msgid "" +" le fichier modele3D.ply est conservé sous un autre " +"nom." +msgstr "" +" The modele3D.ply file in stored with another name." + +#: aperodedenis.py:6708 +msgid "menu Vidéo :" +msgstr "Video menu:" + +#: aperodedenis.py:6709 +msgid "" +" - Options : indiquer le nom de la camera (GoPro, smartphone...), sa " +"focale, sa focale equivalente 35mm" +msgstr "" +" Options: indicate the name of the camera(GoPro, smartphone...), its " +"focal length, its equivalent focal length 35mm" + +#: aperodedenis.py:6710 +msgid " et le nombre d'images à conserver par seconde de film" +msgstr " and the number of picture to keep by second of film" + +#: aperodedenis.py:6711 +msgid "" +" Le nom permet de faire le lien avec DicoCamera.xml qui contient la " +"taille du capteur." +msgstr "" +" The name allows to link with DicoCamera.xml which contains the size " +"of the sensors." + +#: aperodedenis.py:6712 +msgid " Les focales seront recopiées dans l'exif des images." +msgstr " Focal length will be copied to pictures exif." + +#: aperodedenis.py:6713 +msgid "" +" Le nombre d'images par seconde sera utilisé pour la sélection des " +"meilleures images." +msgstr "" +" The number of pictures per second will be used to select the best " +"pictures." + +#: aperodedenis.py:6714 +msgid " Remarque :" +msgstr " Note:" + +#: aperodedenis.py:6715 +msgid "" +" Il faut indiquer dans DicoCamera la taille du capteur " +"effectivement utilisée par la fonction camera," +msgstr "" +" You need to indicate the size of the sensors used by the camera " +"function in DicoCamera," + +#: aperodedenis.py:6716 +msgid "" +" taille qui peut être inférieure à la taille du capteur utilisée " +"pour les photos." +msgstr "" +" size which can be lower to the size of the sensors used to take " +"pictures." + +#: aperodedenis.py:6717 +msgid " Voir par exemple pour une camera Gopro :" +msgstr " For instance, for a GoPro camera:" + +#: aperodedenis.py:6719 +msgid "" +" - Nouveau chantier : choisir une video : choisir un fichier video " +"issu d'une camera ou d'une GoPro." +msgstr "" +" - New Project: choose a video: choose a video file from a camera or a " +"GoPro." + +#: aperodedenis.py:6720 +msgid "" +" La vidéo sera décompactée en images, l'exif sera créé avec les " +"informations en options." +msgstr "" +" The video will be uncompressed in picture, the exif will be create " +"with the options information." + +#: aperodedenis.py:6721 +msgid "" +" Cette étape nécessite la présence de l'outil ffmpeg sous le " +"répertoire bin de MicMac (dépend de la version de MicMac)." +msgstr "" +" This step require the ffmpeg tool in the directory of MicMac\\bin. " +"(Depend on MicMac's version)" + +#: aperodedenis.py:6722 +msgid "" +" Un nouveau chantier est créé avec les options suivante : Line pour " +"Tapioca et FishEyeBasic pour Tapas." +msgstr "" +" A new project is created with following options: Line for Tapioca " +"en FishEyeBasic for Tapas." + +#: aperodedenis.py:6723 +msgid "" +" - Sélection des images : il est raisonnable de ne garder que quelques " +"images par seconde de film." +msgstr "" +" - Pictures selection: it would be best if only a few pictures per " +"second of film are recorded." + +#: aperodedenis.py:6724 +msgid "" +" Le nombre d'images conservées par seconde est indiqué dans les " +"options." +msgstr "" +" The number of pictures stored per second can be found in the " +"options." + +#: aperodedenis.py:6725 +msgid "" +" Chaque seconde de film les 'meilleures' images seront retenues, les " +"autres effacées." +msgstr "" +" Each second of film, the best pictures will be kept, the others " +"removed." + +#: aperodedenis.py:6726 +msgid "" +" Attention : cette étape n'est pas effective pour toutes les " +"versions de MicMac. La version mercurial 5508 fonctionne." +msgstr "" +" Warning : this step does not work for all MicMac versions. The " +"mercurial 5508 version works." + +#: aperodedenis.py:6727 +msgid "" +" Une fois les images sélectionnées le chantier est créé : utiliser " +"le menu MicMac comme pour un chantier normal." +msgstr "" +" Once the pictures selected, the project is created: use the MicMac " +"menu to go on like a normal project." + +#: aperodedenis.py:6728 +msgid "menu Outils :" +msgstr "Tools menu:" + +#: aperodedenis.py:6729 +msgid "" +" - Affiche le nom et la focale de l'appareil photo : fabricant, modèle " +"et focale de la première photo." +msgstr "" +" - Display the name and focal length of the camera: manufacturer, " +"model and focal length of the first picture." + +#: aperodedenis.py:6730 +msgid "" +" Il y a 2 types de focales : focale effective et focale équivalente " +"35 mm." +msgstr "" +" There are two focal length types: effective focal length and " +"equivalent focal length 35mm." + +#: aperodedenis.py:6731 +msgid "" +" Indique si l'appareil photo est connu dans '/XML MicMac/DicoCamera." +"xml'." +msgstr " Shows if the camera is known in '/XML MicMac/DicoCamera.xml'." + +#: aperodedenis.py:6732 +msgid "" +" - Affiche toutes les focales des photos : focales et focales " +"equivalentes en 35mm." +msgstr "" +" - Display all pictures focal length: effective focal length and " +"equivalent focal length 35mm." + +#: aperodedenis.py:6733 +msgid "" +" Si les focales ne sont pas identiques pour toutes les photos : " +"utiliser la calibration intrinséque de tapas." +msgstr "" +" If all focal length are not the same for all pictures: use Tapas's " +"intrinsic calibration." + +#: aperodedenis.py:6734 +msgid "" +" - Mettre à jour DicoCamera.xml : ajouter la taille du capteur dans '/" +"XML MicMac/DicoCamera.xml'." +msgstr "" +"- Update DicoCamera.xml: add sensor size in '/XML MicMac/DicoCamera.xml'." + +#: aperodedenis.py:6735 +msgid "" +" La taille du capteur dans DicoCamera.xml est requise si la focale " +"équivalente 35mm est absente de l'exif." +msgstr "" +" The size of the sensors from DicoCamera.sml is required if the " +"equivalent focal length 35mm is not in the exif." + +#: aperodedenis.py:6736 +msgid "" +" La taille du capteur facilite les calculs et améliore les résultats." +msgstr "Sensor size ease calculations and improve results." + +#: aperodedenis.py:6737 +msgid "" +" La taille du capteur se trouve sur le site du fabricant ou sur " +"http://www.dpreview.com." +msgstr "" +" The size of the sensors can be found on the manufacturer website or " +"on http://www.dpreview.com." + +#: aperodedenis.py:6738 +msgid "" +" - Qualité des photos du dernier traitement : calcule le nombre moyen " +"de points homologues par photo." +msgstr "" +" - Last processing of the quality of the pictures: calculate the " +"average number of tie-points per picture." + +#: aperodedenis.py:6739 +msgid "" +" Si des photos présentent des moyennes très faibles elles peuvent " +"faire échouer le traitement." +msgstr "" +" If some pictures shows a very low average they can make the process " +"fails." + +#: aperodedenis.py:6740 +msgid "" +" - Qualité des photos 'Line' : calcule le nombre moyen de points " +"homologues par photo en mode 'Line', taille 1000." +msgstr "" +" - Quality of the 'Line' pictures: calculate the average number of tie-" +"points per picture in 'Line' mode, size 1000." + +#: aperodedenis.py:6741 +msgid "" +" - Qualité des photos 'MulScale ou All' : calcule le nombre moyen de " +"points homologues par photo, taille 1000.'." +msgstr "" +" - Quality of the 'MulScale' or 'All' pictures: calculate the average " +"number of tie-points per picture in 'Line' mode, size 1000." + +#: aperodedenis.py:6742 +msgid "" +" Ce nombre informe sur la qualité relative des photos au sein du " +"chantier." +msgstr "" +" This number gives an idea of pictures relative quality in this " +"project." + +#: aperodedenis.py:6743 +msgid "" +" La présence de photos avec peu de points homologues peut faire " +"échouer le traitement." +msgstr "" +" The lack of tie-points among pictures could make the process fails." + +#: aperodedenis.py:6744 +msgid "" +" Il est parfois préférable de traiter peu de photos mais de bonne " +"qualité." +msgstr " Il is sometimes better to use a few pictures of high-quality." + +#: aperodedenis.py:6745 +msgid "" +" - Modifier l'exif des photos : permet la création et la modification " +"des exifs des photos du chantier." +msgstr "" +" - Edit pictures exif: allows to create and edit pictures exif from " +"the project." + +#: aperodedenis.py:6746 +msgid "menu Paramétrage :" +msgstr "Settings menu:" + +#: aperodedenis.py:6747 +msgid "" +" - Affiche les paramètres : visualise les chemins de micmac\\bin, " +"d'exiftool, du fichier pour visualiser les .ply (Meshlab ou Cloud Compare)," +msgstr "" +" - Display settings: shows micmac\\bin, exiftool, .ply opener " +"(Meshlab or Cloud Compare) paths," + +#: aperodedenis.py:6748 +msgid "" +" ainsi que le répertoire où se trouve les fichiers paramètres de " +"l'interface." +msgstr " as the settings files directory of the GUI." + +#: aperodedenis.py:6749 +msgid "" +" Ces paramètres sont sauvegardés de façon permanente dans le " +"fichier :" +msgstr " These settings are permanently saved in the file:" + +#: aperodedenis.py:6751 +msgid "" +" - Désigner le répertoire MicMac\\bin : répertoire où se trouvent les " +"modules de MicMac " +msgstr "" +" - Select the MicMac\\bin directory: directory where MicMac modules " +"can be found." + +#: aperodedenis.py:6752 +msgid "" +" Si plusieurs versions sont installées cet item permet de changer " +"facilement la version de MicMac utilisée." +msgstr "" +" If several versions are installed, you can easily change the one " +"you want to use." + +#: aperodedenis.py:6753 +msgid "" +" - Désigner l'application exiftool, utile pour modifier les exif (elle " +"se trouve sous micMac\\binaire-aux)." +msgstr "" +" - Shows exiftool application, useful to edit exifs. (Can be found in " +"MicMac\\binaire-aux)." + +#: aperodedenis.py:6754 +msgid "" +" - Désigner l'application convert d'ImageMagick, utile pour convertir " +"les gif, tif et bmp en jpg (elle se trouve sous micMac\\binaire-aux)." +msgstr "" +" - Show ImageMagick's convert application, to convert gif, tig and bmp " +"into jpg. (Can be found in MicMac\\binaire-aux)." + +#: aperodedenis.py:6755 +msgid "" +" - Désigner l'application ouvrant les fichiers .PLY. Ce peut être " +"Meshlab, CloudCompare ou autre." +msgstr "" +" - Show the .ply opener. It can be Meshlab, CloudCompare or anything " +"else." + +#: aperodedenis.py:6756 +msgid " Sous Windows Meshlab se trouve sous un répertoire nommé VCG." +msgstr " On Windows, Meshlab can be found in a directory named 'VCG'." + +#: aperodedenis.py:6757 +msgid " - Activer/désactiver le 'tacky' message de lancement" +msgstr " - Activate/Desactivate the launching tacky message." + +#: aperodedenis.py:6758 +msgid "menu Aide :" +msgstr "Help menu:" + +#: aperodedenis.py:6759 +msgid "" +" - Pour commencer : à lire lors de la prise en main de l'interface." +msgstr "" +" - Get started: should be read to learn how to use the Graphical User " +"Interface." + +#: aperodedenis.py:6760 +msgid " - Aide : le détail des items de menu." +msgstr " - Help: détails about menu's items." + +#: aperodedenis.py:6761 +msgid " - Quelques conseils : sur la prise de vue et les options." +msgstr " - Advices: about options and shooting" + +#: aperodedenis.py:6762 +msgid " - Historique : les nouveautés de chaque version." +msgstr " - Changelog: what's new in each version" + +#: aperodedenis.py:6763 +msgid " - A propos" +msgstr " - About" + +#: aperodedenis.py:6764 +msgid " Quelques précisions :" +msgstr "A few détails:" + +#: aperodedenis.py:6765 +msgid "" +" Cette version a été développée sous Windows XP et Seven avec micmac rev " +"5508 d'avril 2015." +msgstr "" +"This version was developed on Windows Xp and Seven with micmac rev 5508 from " +"april 2015." + +#: aperodedenis.py:6766 +msgid "" +" L'utilisation d'autres versions de Micmac a été testée, jusqu'à la version " +"6219." +msgstr "Other MicMac versions were tested, to version 6219." + +#: aperodedenis.py:6767 +msgid " Le fonctionnement sous Ubuntu Trusty a été vérifié." +msgstr "Proper functioning was verified on Ubuntu Trusty." + +#: aperodedenis.py:6768 +msgid " Consulter la documentation de MicMac, outil réalisé par l'IGN." +msgstr "See MicMac documentation, a tool realised by the IGN." + +#: aperodedenis.py:6769 +msgid " Consulter le guide d'installation et de prise en main d'AperoDeDenis." +msgstr "See the AperoDeDenis's starting guide." + +#: aperodedenis.py:6778 +msgid "" +"Interface graphique pour lancer les modules de MICMAC : quelques conseils." +msgstr "Graphic User Interface to launch MICMAC modules: a few détails." + +#: aperodedenis.py:6779 +msgid "Prises de vue :" +msgstr "Shooting:" + +#: aperodedenis.py:6780 +msgid "" +" - Le sujet doit être immobile durant toutes la séance de " +"prise de vue." +msgstr "" +" - The subject must not move during the shooting session." + +#: aperodedenis.py:6781 +msgid "" +" - Le sujet doit être bien éclairé, la prise de vue en plein " +"jour doit être recherchée." +msgstr "" +" - The subject must be well lightened, preferably by daylight." + +#: aperodedenis.py:6782 +msgid "" +" - Les photos doivent être nettes, attention à la profondeur " +"de champ :" +msgstr "" +" - Pictures must be clear, pay attention to the depth of " +"field:" + +#: aperodedenis.py:6783 +msgid "" +" utiliser la plus petite ouverture possible (nombre F le " +"plus grand, par exemple 22)." +msgstr " use the smallest gap you can (bigger F, like 22)" + +#: aperodedenis.py:6784 +msgid "" +" - Les photos de personnes ou d'objet en mouvement sont " +"déconseillées" +msgstr "" +" - Pictures of moving people or object are not indicated.." + +#: aperodedenis.py:6785 +msgid "" +" - Les surfaces lisses ou réfléchissantes sont défavorables." +msgstr " - Smooth or reflective surfaces are unsuitable." + +#: aperodedenis.py:6786 +msgid "" +" - Si le sujet est central prendre une photo tous les 20°, " +"soit 9 photos pour un 'demi-tour', 18 pour un tour complet." +msgstr "" +" - If the subject is in the center, take a picture by 20° " +"step, meaning that 9 pictures for a semi-circle around the subjet or 18 for " +"a whole full turn." + +#: aperodedenis.py:6787 +msgid "" +" - Si le sujet est en 'ligne' le recouvrement entre photos " +"doit être des 2/3." +msgstr "" +" - If the subject is in 'line', the overlap ratio must be " +"2/3." + +#: aperodedenis.py:6788 +msgid "" +" - Tester la 'qualité' des photos au sein du chantier (voir " +"les items du menu Outils)." +msgstr "" +" - Check the quality of the pictures in the project (in the " +"Tools menu)." + +#: aperodedenis.py:6789 +msgid "" +" les photos ayant un mauvais score (voir le menu Outils/" +"Qualité des photos 'All') doivent être supprimées du chantier : " +msgstr "" +" The pictures with a bad score (see the menu Tools / " +"Quality of photos 'All') must be removed from the project:" + +#: aperodedenis.py:6790 +msgid "" +" une seule mauvaise photo peut faire échouer le traitement." +msgstr "" +" A single bad picture may cause the processing to fail." + +#: aperodedenis.py:6791 +msgid "" +" - La présence des dimensions du capteur de l'appareil dans " +"DIcoCamera.xml améliore le traitement." +msgstr "" +" - The size of the sensors of the camera in DicoCamera.xml " +"can improve processing." + +#: aperodedenis.py:6792 +msgid "" +" Cette présence est obligatoire si l'exif ne présente pas " +"la focale équivalente 35mm." +msgstr "" +" It is required if the exif does not have the equivalent " +"focal length 35mm." + +#: aperodedenis.py:6793 +msgid "" +" Pour ajouter la taille du capteur utiliser le menu " +"'Outils//mettre à jour DicoCamera'." +msgstr "" +" To add the size of the sensor, use the 'Tools/Update " +"DicoCamera' menu." + +#: aperodedenis.py:6794 +msgid " Précautions : " +msgstr " Cautions:" + +#: aperodedenis.py:6795 +msgid "" +" Ne pas utiliser la fonction autofocus. Deux focales " +"différentes maximum pour un même chantier." +msgstr "" +" Don't use autofocus. Two different focal length maximum for " +"a same project." + +#: aperodedenis.py:6796 +msgid "" +" Si il y a 2 focales différentes utiliser la calibration " +"intrinsèque de Tapas." +msgstr "" +" If these are two different focal length, use Tapas " +"intrinsic calibration." + +#: aperodedenis.py:6797 +msgid "" +" Eviter aussi la fonction 'anti tremblement' qui agit en " +"modfiant la position du capteur." +msgstr "" +" Avoid to use the 'Anti-shake' function which changes the " +"position of the sensors." + +#: aperodedenis.py:6798 +msgid "Options :" +msgstr "Options:" + +#: aperodedenis.py:6799 +msgid "" +" - Tapioca : si le sujet est central conserver les paramètres " +"par défaut." +msgstr "" +" -Tapioca : if the target is in the center, keep the default " +"settings." + +#: aperodedenis.py:6800 +msgid "" +" L'échelle est la taille réduite de l'image (en " +"pixels, ou -1 pour l'image entière) pour la recherche des points homologues." +msgstr "" +" The scale is the reduced size of the picture (in " +"pixels, or -1 for the whole picture) used for the tie-points search." + +#: aperodedenis.py:6801 +msgid "" +" Si le sujet est en ligne choisir 'line' dans les " +"options de Tapioca, " +msgstr "" +" If the subject is in " +"line, choose 'line' in Tapioca's options." + +#: aperodedenis.py:6802 +msgid "" +" puis delta = 1, si les " +"photos se recouvrent à moitiè, " +msgstr "" +" then delta = 1 if " +"pictures overlaps themselves to the half," + +#: aperodedenis.py:6803 +msgid "" +" ou delta = 2 voire +, " +"si le recouvrement est plus important." +msgstr "" +" or delta = 2 or more, if " +"they overlap themselves more." + +#: aperodedenis.py:6804 +msgid "" +" L'option ALl recherche les points homologues sur " +"toutes les paires de photos (ce qui peut faire beaucoup !)" +msgstr "" +" 'ALL' options will search tie-points on all " +"pictures pairs (whichcan beuch!)" + +#: aperodedenis.py:6805 +msgid "" +" L'option MulScale recherche les points homologues " +"en 2 temps :" +msgstr "" +" MulScale option search tie-point in 2 steps:" + +#: aperodedenis.py:6806 +msgid "" +" 1) sur toutes les paires avec une taille de " +"photo réduite (typiquement 300)" +msgstr "" +" 1) On all pairs with a picture size reduced " +"(typically 300)" + +#: aperodedenis.py:6807 +msgid "" +" 2) Seules les paires de photos ayant eu au " +"moins 2 points homologues à cette échelle seront" +msgstr "" +" 2) Only the pairs having at least two tie-" +"points on this scale will" + +#: aperodedenis.py:6808 +msgid "" +" retenues pour rechercher les points " +"homologues à la seconde échelle. Gain de temps important possible." +msgstr "" +" be used for the tie-points search on the " +"second scale. This can save a lot of time !" + +#: aperodedenis.py:6809 +msgid "" +" - Tapas : si l'appareil photo est un compact ou un smartphone " +"choisir RadialBasic, " +msgstr "" +" - Tapas : if the camera is a compact or a smartphone, choose " +"RadialBasic," + +#: aperodedenis.py:6810 +msgid "" +" si l'appareil photo est un reflex haut de gamme " +"choisir RadialExtended " +msgstr "" +" if the camera is a top of the line reflex, choose " +"RadialExtended" + +#: aperodedenis.py:6811 +msgid "" +" si l'appareil photo est de moyenne gamme choisir " +"RadialStd" +msgstr "" +" if the camera is an average range camera, choose " +"RadialStd" + +#: aperodedenis.py:6812 +msgid "" +" si les photos ont 2 focales alors choisir toutes " +"celles qui ont la plus grande focale pour la calibration intrinsèque." +msgstr "" +" if the pictures have two diffrent focal length, " +"choose those with a bigger focal length for the intrinsic calibration" + +#: aperodedenis.py:6813 +msgid "" +" L'arrêt aprés Tapas est conseillé : la " +"visualisation du nuage de points non densifié" +msgstr "" +" Stopping after Tapas is indicated: displaying " +"undensified point cloud" + +#: aperodedenis.py:6814 +msgid "" +" permet de définir un masque, 2D ou 3D, pour l'étape " +"suivante." +msgstr "" +" allow to create a 2D or 3D mask for the next step." + +#: aperodedenis.py:6815 +msgid "" +" - Calibration : permet de définir un repère et une métrique " +"(axe, plan et distance, tous obligatoires)." +msgstr "" +" - Calibration: allows to define a frame and a metric (axis, " +"plane and distance, all mandatory)" + +#: aperodedenis.py:6816 +msgid "" +" - Malt : pour le mode GeomImage indiquer une ou plusieurs " +"images maîtresses." +msgstr "" +" - Malt: for the GeomImage mode, select one or several master " +"pictures." + +#: aperodedenis.py:6817 +msgid "" +" Seuls les points visibles sur ces images seront " +"conservés dans le nuage de points." +msgstr "" +" Only the visible points on master pictures " +"will bie displayed in the point cloud." + +#: aperodedenis.py:6818 +msgid "" +" Sur ces images maîtresses tracer les masque " +"délimitant la partie 'utile' de la photo." +msgstr "" +" Draw the mask delimiting the useful area of these " +"pictures." + +#: aperodedenis.py:6819 +msgid "" +" Le résultat sera mis en couleur suivant les images " +"maitresses." +msgstr "" +" The result will be colored according to master " +"pictures." + +#: aperodedenis.py:6820 +msgid "" +" (éviter trop de recouvrement entre les maîtresses !)." +msgstr "" +" (avoid too many overlap between master pictures !)" + +#: aperodedenis.py:6821 +msgid "" +" Le traitement avec masque sera accéléré et le " +"résultat plus 'propre'." +msgstr "" +" Processing with a mask will be quicker and the " +"result will be cleaner." + +#: aperodedenis.py:6822 +msgid "" +" - C3DC : propose de définir un masque en 3D qui conservera " +"tout le volume concerné." +msgstr "" +" - C3DC: allows to define a 3D mask keeping the concerned " +"volume." + +#: aperodedenis.py:6823 +msgid "" +" Alternative à Malt, le traitement est beaucoup plus " +"rapide. Nécessite la dernière version de MicMac." +msgstr "" +" This options is a malt alternative in which the " +"process is far quicker. The last version of MicMac is required." + +#: aperodedenis.py:6824 +msgid "" +" - GPS : définir au moins 3 points cotés et les placer sur 2 " +"photos. La trace indique s'ils sont pris en compte" +msgstr "" +" - GPS: allows to define at least three points and place it on " +"two pictures. The log shows if they're taken into account." + +#: aperodedenis.py:6825 +msgid "Si MicMac ne trouve pas d'orientation ou pas de nuage de points :" +msgstr "If MicMac can't find any orientation or point cloud:" + +#: aperodedenis.py:6826 +msgid "" +" - Examiner la qualité des photos (utiliser le menu outils/" +"Qualité des photos): ." +msgstr "" +" - Check the quality of the pictures (use the Tools/Quality of " +"the pictures):" + +#: aperodedenis.py:6827 +msgid "" +" 1) Eliminer les photos ayant les plus mauvais scores" +msgstr " 1) Exclude pictures with the worst scores" + +#: aperodedenis.py:6828 +msgid "" +" 2) si ce n'est pas suffisant ne garder que les " +"meilleures photos (typiquement : moins de 10)" +msgstr "" +" 2) If this is not enough, keep the best pictures " +"(less than 10)" + +#: aperodedenis.py:6829 +msgid "" +" Penser que des photos floues ou avec un sujet " +"brillant, lisse, mobile, transparent, vivant sont défavorables." +msgstr "" +" Keep in mind that blured pictures, or with a " +"shiny, smooth, transparent or moving subject must be avoided." + +#: aperodedenis.py:6830 +msgid "" +" 3) Augmenter l'échelle des photos pour tapioca, " +"mettre -1 au lieu de la valeur par défaut." +msgstr "" +" 3) Increase pictures scale for Tapioca, give it a -1 " +"value instead of the default value." + +#: aperodedenis.py:6831 +msgid "" +" 4) modifier le type d'appareil pour Tapas (radialstd " +"ou radialbasic)" +msgstr "" +" 4) Edit the camera type for Tapas (radialstd or " +"radialbasic)" + +#: aperodedenis.py:6832 +msgid "" +" 5) vérifier la taille du capteur dans dicocamera, " +"nécessaire si la focale equivalente 35 mm est absente de l'exif" +msgstr "" +" 5) Check the sensor size in Dicocamera.xml, required " +"if the equivalent focal length 35mm is not in the exif" + +#: aperodedenis.py:6833 +msgid "" +" 6) examiner la trace synthétique et la trace " +"complète : MicMac donne quelques informations" +msgstr "" +" 6) Check the syntethic and complete log: MicMac can " +"give you some important information" + +#: aperodedenis.py:6834 +msgid "" +" 7) consulter le forum micmac (http://forum-micmac." +"forumprod.com)" +msgstr "" +" 7) Check MicMac forum (http://forum-micmac.forumprod." +"com)" + +#: aperodedenis.py:6835 +msgid "" +" 8) faites appel à l'assistance de l'interface (voir " +"adresse dans l'a-propos)" +msgstr "" +" 8) Ask the GUI support (see mail in Help/About menu)" + +#: aperodedenis.py:6844 +msgid " Pour commencer avec l'interface graphique MicMac :" +msgstr " To get started with the MicMac's Graphical User Interface: " + +#: aperodedenis.py:6845 +msgid " Tout d'abord : installer MicMac." +msgstr " First : install MicMac" + +#: aperodedenis.py:6846 +msgid "" +" Puis : installer Meshlab ou CloudCompare (pour afficher les nuages de " +"points)" +msgstr " Nest : install Meshlab or CloudCompare (to display point clouds)" + +#: aperodedenis.py:6847 +msgid " Ensuite, dans cette interface graphique :" +msgstr " Next, in the graphical User Interface:" + +#: aperodedenis.py:6848 +msgid "" +"1) Paramètrer l'interface : indiquer ou se trouvent le répertoire bin de " +"MicMac et l'éxécutable Meshlab ou CloudCompare." +msgstr "" +"1) Interface parameters: set directory of MicMac\\bin and Meshlab or " +"Cloudcompare's executable." + +#: aperodedenis.py:6849 +msgid "" +" Indiquer éventuellement ou se trouvent exiftool et convert d'ImageMagick " +"(en principe sous MicMac\\binaire-aux)." +msgstr "" +" You can also indicate exiftool and ImageMagick's convert directories " +"(normally Under MicMac\\binaire-aux)." + +#: aperodedenis.py:6850 +msgid "" +"2) Choisir quelques photos, par exemple du jeu d'essai gravillons, au moins " +"3 mais pas plus de 6 pour commencer (menu MicMac)." +msgstr "" +"2) Choose some pictures, at least three but no more than six for start " +"(MicMac menu)." + +#: aperodedenis.py:6851 +msgid "3) Lancer MicMac en laissant les paramètres par défaut (menu MicMac)." +msgstr "3) Launch MicMac and choose default settings (MicMac menu)" + +#: aperodedenis.py:6852 +msgid "" +" Si tout va bien une vue en 3D non densifiée doit s'afficher, patience : " +"cela peut être long." +msgstr "" +" If everything's fine, a non densified 3D view must be displayed: be " +"patient, it can be long." + +#: aperodedenis.py:6853 +msgid "" +"4) Si tout va bien alors modifier les options pour la suite du traitement " +"(Malt ou C3DC) (voir la doc)." +msgstr "" +"4) If everything works, edit options for next processing (Malt or C3DC) (see " +"doc)." + +#: aperodedenis.py:6854 +msgid " Puis re lancer MicMac pour obtenir une vue 3D densifiée." +msgstr " Then relaunch MicMac to generate a densified 3D view." + +#: aperodedenis.py:6855 +msgid "" +"5) Si tout ne va pas bien re 'lancer MicMac' et annuler le traitement, puis :" +msgstr "5) If something doesn't work, cancel processing and then: " + +#: aperodedenis.py:6856 +msgid " Lire 'quelques conseils' (menu Aide)." +msgstr " Read 'Advices' (Help menu)" + +#: aperodedenis.py:6857 +msgid " Tester la qualité des photos (menu Outils)." +msgstr " Test the quality of the pictures (Tools menu)" + +#: aperodedenis.py:6858 +msgid " Examiner les traces (menu Edition)," +msgstr " Read logs (Edit menu)" + +#: aperodedenis.py:6859 +msgid " Consulter l'aide (menu Aide)," +msgstr " Read Help (Help menu)" + +#: aperodedenis.py:6860 +msgid "" +" Consulter le guide d'installation et de prise en main de l'interface." +msgstr " See installation and grip guide of the GUI" + +#: aperodedenis.py:6861 +msgid " Consulter le forum MicMac sur le net, consulter la doc MicMac." +msgstr " See MicMac forum and doc." + +#: aperodedenis.py:6862 +msgid "6) Si une solution apparaît : modifier les options (menu MicMac)." +msgstr "6) If a solution appear: edit options (MicMac menu)" + +#: aperodedenis.py:6863 +msgid " puis relancer le traitement." +msgstr " then relaunch the process." + +#: aperodedenis.py:6864 +msgid "" +"7) Si le problème persiste faire appel à l'assistance de l'interface " +"(adresse mail dans l'A-propos)" +msgstr "7) If you can't solve the problem, mail the assistance (mail in About)" + +#: aperodedenis.py:6869 +msgid "Historique des versions diffusées sur le site de l'IGN" +msgstr "History of published versions on IGN's website" + +#: aperodedenis.py:6871 +msgid "" +"Version 1.5 : première version diffusée sur le site de l'IGN le 23/11/2015." +msgstr "Version 1.5:" + +#: aperodedenis.py:6872 +msgid "" +"Version 1.55 : sous Windows le fichier paramètre est placé sous le " +"répertoire APPDATA de l'utilisateur," +msgstr "" +"Version 1.55 : On Windows, the settings file is saved in the user's APPDATA " +"directory," + +#: aperodedenis.py:6873 +msgid "" +"ce qui règle les questions relatives aux droits d'accès en écriture. Mise en " +"ligne le 04/12/2015." +msgstr "solving writing permissions problems. 04/12/2015." + +#: aperodedenis.py:6874 +msgid "Version 1.60 : ajout des fonctions :" +msgstr "Version 1.60 : Functions added :" + +#: aperodedenis.py:6875 +msgid "- Qualité des photos lors du dernier traitement" +msgstr "- Quality of the pictures of last process." + +#: aperodedenis.py:6876 +msgid "- Exporter le chantier en cours" +msgstr "-Export current project" + +#: aperodedenis.py:6877 +msgid "" +"- Importer un chantier (permet de recopier le chantier sur un autre " +"répertoire, disque, ordinateur, système d'exploitation)" +msgstr "" +"-Importing project (allow to copy the project in a new directory, disk, " +"computer or operating system)" + +#: aperodedenis.py:6878 +msgid "- Les fichiers 'trace' sont enregistrés au format utf-8." +msgstr "- Log files are now saved in utf-8 format." + +#: aperodedenis.py:6879 +msgid "Version 2.00 : ajout des fonctions :" +msgstr "Version 2.00 : Functions added :" + +#: aperodedenis.py:6880 +msgid "- Choix de photos pour la calibration intrinsèque par Tapas." +msgstr "- Pictures selection for intrinsic calibration by Tapas." + +#: aperodedenis.py:6881 +msgid "" +"- Possibilité de relancer Malt sans relancer Tapioca/Tapas tout en " +"conservant les images 3D générées." +msgstr "" +"- Possibility to relaunch Malt without relaunching Tapioca/Tapas and " +"conserving 3D pictures generated." + +#: aperodedenis.py:6882 +msgid "" +"- Conservation de plusieurs fichiers modele3D.ply après Malt pour un même " +"chantier." +msgstr "" +"- Retention of several 3Dmodels .ply files after Malt for a same project." + +#: aperodedenis.py:6883 +msgid "" +"- Choix du niveau de zoom d'arrêt de la procédure Malt : de 1 (par défaut) à " +"8." +msgstr "" +"- Choice in zoom level for stopping the Malt process: 1 (default) to 8." + +#: aperodedenis.py:6884 +msgid "" +"- Création de tous les fichiers .ply correspondants à tous les niveaux de " +"zoom calculés." +msgstr "" +" - Creation of all .ply files corresponding to the different zoom levels " +"calculated." + +#: aperodedenis.py:6885 +msgid "" +"- Ajout d'un item du menu édition listant et visualisant toutes les images " +"3D générées." +msgstr "" +" - Item added in the Edit menu which list and allows to display all 3D " +"generated pictures." + +#: aperodedenis.py:6886 +msgid "" +"- Choix du nombre de photos à retenir autour de l'image maître pour Malt." +msgstr "" +" - Choice of the number of pictures to use with the Malt's master picture." + +#: aperodedenis.py:6887 +msgid "" +"- Traitement des vidéos (par exemple GoPro) : décompactage, sélection, mise " +"à jour de l'exif" +msgstr "" +" - Video processing (with GoPro, for instance): unpacking, selecting, exif " +"update." + +#: aperodedenis.py:6888 +msgid "" +"- Ajout de deux contrôles sur le lot des photos : mêmes dimensions, même " +"focale." +msgstr "" +" - Two new controls of pictures pack: same dimensions and same focal length." + +#: aperodedenis.py:6889 +msgid "- Ajout d'un item 'historique' dans le menu Aide." +msgstr " - Item \"History log\" added to the Help menu." + +#: aperodedenis.py:6890 +msgid "- Ajout d'un item du menu édition fusionnant les images 3D." +msgstr " - Item \"Merge 3D pictures\" in the Edit menu." + +#: aperodedenis.py:6890 +msgid "Version 2.10" +msgstr "Version 2.10:" + +#: aperodedenis.py:6891 +msgid "- Plusieurs images maîtresses, plusieurs masques." +msgstr "- Several master pictures and masks." + +#: aperodedenis.py:6892 +msgid "- Conversion automatique des fichiers PNG, BMP, GIF, TIF en JPG" +msgstr "- Automatic conversion of fil formats PNG, BMP, GIF and TIF into JPG." + +#: aperodedenis.py:6893 +msgid "" +"- Ajout d'un item du menu Outils permettant de modifier les exifs. Diffusion " +"restreinte à la DTer NC le 16/02/2016" +msgstr "" +"- An item was added in the Tools menu, that allow to edit exifs. Restricted " +"diffusion at DTer NC on 16/02/2016" + +#: aperodedenis.py:6894 +msgid "" +"- Maintien des options compatibles lors du choix de nouvelles photos. " +"Février 2016" +msgstr "" +"- Maintaining compatibles options when choosing new pictures. February 2016" + +#: aperodedenis.py:6894 +msgid "Version 2.20 :" +msgstr "Version 2.20:" + +#: aperodedenis.py:6895 +msgid "Version 2.30 : " +msgstr "Version 2.30:" + +#: aperodedenis.py:6896 +msgid "- Modification des options par défaut dans le menu outils." +msgstr "- Default options can be edited in the Tools menu." + +#: aperodedenis.py:6897 +msgid "- Choix de l'option (Statue ou QuickMac) pour C3DC. Avril 2016" +msgstr " - Option choice (C3DC or QuickMac) for C3DC. April 2016" + +#: aperodedenis.py:6897 +msgid "Version 2.40 :" +msgstr "Version 2.40:" + +#: aperodedenis.py:6898 +msgid "" +"- Référentiel GPS calculé après Tapas (et toujours avant Malt). La virgule " +"est un séparateur décimal accepté." +msgstr "" +" - GPS repository calculated after Tapas (still before Malt). The comma is " +"accepted as a decimal separator." + +#: aperodedenis.py:6898 +msgid "Version 2.45 :" +msgstr "Version 2.45:" + +#: aperodedenis.py:6899 +msgid "" +"- Possiblité d'appliquer la calibration GPS sans relancer malt. Mai 2016" +msgstr " - GPS calibration can be applied without relaunching Malt. May 2016" + +#: aperodedenis.py:6900 +msgid "" +"- Ajout de Tawny aprés Malt en mode Ortho, désactivation du message de " +"lancement. Juin 2016" +msgstr "" +" - Adding Tawny after Malt in Ortho mode, launching message can be " +"desactivated. June 2016" + +#: aperodedenis.py:6900 +msgid "Version 2.50 :" +msgstr "Version 2.50:" + +#: aperodedenis.py:6901 +msgid "- Version bilingue Français/Anglais. Octobre 2016" +msgstr "- Bilingual version French / English. October 2016" + +#: aperodedenis.py:6901 +msgid "Version 3.00 :" +msgstr "Version 3.00:" + +#: aperodedenis.py:6902 +msgid "- Choix des N meilleures photos pour un nouveau dossier. Novembre 2016" +msgstr "- Choice of N best photos for a new folder. November 2016" + +#: aperodedenis.py:6902 +msgid "Version 3.10 :" +msgstr "Version 3.10:" + +#: aperodedenis.py:6903 +msgid "Version 3.20 :" +msgstr "Version 3.20:" + +#: aperodedenis.py:6903 aperodedenis.py:6911 +msgid "janvier 2017" +msgstr "January 2017" + +#: aperodedenis.py:6904 +msgid "" +"- Ajout d'un choix pour Malt : AperoDeDenis, l'interface recherche pour vous " +"les maîtresses et les photos correspondantes" +msgstr "" +"- Added a choice for Malt: AperoDeDenis, the interface looks for you the " +"mistresses and the corresponding photos" + +#: aperodedenis.py:6905 +msgid "" +"- Item de sélection des meilleures images pour créer un nouveau chantier. " +"janvier 2017" +msgstr "" +"- Item of selection of the best images to create a new site. January 2017" + +#: aperodedenis.py:6906 +msgid "- Possibilité de saisir une unité avec la distance." +msgstr "- Ability to enter a unit with distance." + +#: aperodedenis.py:6907 +msgid "- Lancement de Tapas accéléré : suppression du controle des photos" +msgstr "- Launch of accelerated Tapas removal of pictures of control" + +#: aperodedenis.py:6908 +msgid "" +"- Les photos autour de la maîtresse pour Malt sont choisies parmi les " +"meilleures en correspondances" +msgstr "" +"- Photos around the mistress for Malt are chosen among the best in matches" + +#: aperodedenis.py:6909 +msgid "- Controle affiné des points GPS, message informatif détaillé" +msgstr "- Refined control of GPS points, detailed informative message" + +#: aperodedenis.py:6910 +msgid "- Possibilité de supprimer UN seul point GPS sur une photo" +msgstr "- Ability to delete a single GPS point on a photo" + +#: aperodedenis.py:6911 +msgid "Version 3.30 :" +msgstr "Version 3.30 :" + +#: aperodedenis.py:6912 +msgid "- Ajout de tarama : création d'une mosaïque aprés Tapas." +msgstr "- Added tarama: creation of a mosaic after Tapas." + +#: aperodedenis.py:6913 +msgid "- le mode Ortho de Malt utilise la mosaïque tarama, avec masque" +msgstr "- Malt's Ortho mode uses the mosaic tarama, with mask" + +#: aperodedenis.py:6914 +msgid "- drapage du nuage densifié par l'ortho mosaïque obtenue par Tawny" +msgstr "- draping of the densified cloud by the ortho mosaic obtained by Tawny" + +#: aperodedenis.py:6915 +msgid "- Possibilité d'inverser les masques 2D" +msgstr "- Possibility of reversing 2D masks" + +#: aperodedenis.py:6916 +msgid "- Ouverture des mosaïques Tarama et Tawny par menu" +msgstr "- Opening Tarama and Tawny mosaics by menu" + +#: aperodedenis.py:6917 +msgid "- Ajout d'un menu 'expert' permettant de saisir une ligne de commande." +msgstr "- Added an 'expert' menu to enter a command line." + +#: aperodedenis.py:6918 +msgid "Version 3.31 :" +msgstr "Version 3.31 :" + +#: aperodedenis.py:6918 +msgid "février 2017" +msgstr "February 2017" + +#: aperodedenis.py:6919 +msgid "" +"- Ajout d'un item du menu 'expert' : recopie les points GPS d'un chantier à " +"un autre." +msgstr "" +"- Added an item from the 'Expert' menu: Copies GPS points from one job site " +"to another." + +#: aperodedenis.py:6929 +msgid "Laboratoire Régional de Rouen" +msgstr "Laboratoire Régional de Rouen" + +#: aperodedenis.py:6929 +msgid "Réalisation Denis Jouin 2015-2016" +msgstr "Created by Denis Jouin 2015 - 2016" + +#: aperodedenis.py:6930 +msgid "Direction Territoriale Normandie Centre" +msgstr "Direction Territoriale Normandie Centre" + +#: aperodedenis.py:6946 +msgid "erreur canvas logo cerema : " +msgstr "Canvas error 'logo cerema':" + +#: aperodedenis.py:7030 +msgid "erreur sauveParamChantier : " +msgstr "error sauveParamChantier:" + +#: aperodedenis.py:7058 +msgid "erreur sauveParamMicMac : " +msgstr "error sauveParamMicMac:" + +#: aperodedenis.py:7059 +msgid "" +"L'interface doit être installée dans un répertoire ou vous avez les droits " +"d'écriture." +msgstr "" +"The Graphical User Interface must be installed in a directory on which you " +"have write permissions." + +#: aperodedenis.py:7060 +msgid "" +"Installer l'interface AperoDeDenis à un emplacement ou vous avez ce droit." +msgstr "Install AperoDeDenis in a directory which on you have this permission." + +#: aperodedenis.py:7061 +msgid "Répertoire actuel : " +msgstr "Current directory:" + +#: aperodedenis.py:7062 +msgid "Erreur rencontrée : " +msgstr "Encountered error: " + +#: aperodedenis.py:7063 +msgid "Problème d'installation" +msgstr "Installation problem: " + +#: aperodedenis.py:7100 +msgid "Erreur restauration param généraux : " +msgstr "Error loading general settings: " + +#: aperodedenis.py:7188 +msgid "Erreur restauration param chantier : " +msgstr "Error loading project settings:" + +#: aperodedenis.py:7198 +msgid "erreur définir fichier trace, est normale lors d'une importation." +msgstr "Error define log trace. Normal when importing." + +#: aperodedenis.py:7369 +msgid "Enregistrer les options saisies ?" +msgstr "Save changes?" + +#: aperodedenis.py:7369 +msgid "Fermer les options." +msgstr "Close options." + +#: aperodedenis.py:7369 aperodedenis.py:7382 aperodedenis.py:7394 +msgid "abandon" +msgstr "abort" + +#: aperodedenis.py:7369 aperodedenis.py:7382 aperodedenis.py:7394 +msgid "enregistrer" +msgstr "save" + +#: aperodedenis.py:7382 +msgid "Enregistrer les options vidéos saisies ?" +msgstr "Save these video options values?" + +#: aperodedenis.py:7382 +msgid "Fermer les options vidéo." +msgstr "Close video options." + +#: aperodedenis.py:7394 +msgid "Enregistrer les valeurs saisies ?" +msgstr "Save choosen values ?" + +#: aperodedenis.py:7394 +msgid "Fermer la modification des exifs." +msgstr "Close exif edit." + +#: aperodedenis.py:7415 +msgid "erreur connexion internet : " +msgstr "Internet connection error:" + +#: aperodedenis.py:7431 +msgid "Nouvelle version de l'interface AperoDeDenis" +msgstr "New version of the AperoDeDenis interface" + +#: aperodedenis.py:7432 +msgid "Nouvelle version disponible sur Internet : " +msgstr "New version available on the Internet:" + +#: aperodedenis.py:7434 +msgid "Téléchargement à l'adresse : " +msgstr "Download at:" + +#: aperodedenis.py:7436 aperodedenis.py:7726 aperodedenis.py:9179 +msgid "OK" +msgstr "OK" + +#: aperodedenis.py:7437 +msgid "Accéder au site" +msgstr "Access the site" + +#: aperodedenis.py:7438 +msgid "Ne plus me le rappeler" +msgstr "Do not remind me anymore" + +#: aperodedenis.py:7453 +msgid "Tous les chantiers sont déjà supprimés." +msgstr "All projects have already been deleted." + +#: aperodedenis.py:7461 +msgid "Chantiers à supprimer" +msgstr "Project to delete" + +#: aperodedenis.py:7465 +msgid "repertoires" +msgstr "directories" + +#: aperodedenis.py:7470 aperodedenis.py:7477 +msgid "Suppression des répertoires de travail superflus" +msgstr "Deleting useless working directories..." + +#: aperodedenis.py:7471 +msgid "Le répertoire suivant va être supprimé, sans mise en corbeille :" +msgstr "Following directory will be deleted for good:" + +#: aperodedenis.py:7472 +msgid "Confirmez" +msgstr "Confirm" + +#: aperodedenis.py:7476 +msgid "ATTENTION : le chantier en cours va être supprimé." +msgstr "Warning: current project will be deleted." + +#: aperodedenis.py:7478 +msgid "Vont être supprimés les répertoires suivants, sans mise en corbeille :" +msgstr "Following directories will be deleted for good:" + +#: aperodedenis.py:7479 +msgid "Confimez" +msgstr "Confirm" + +#: aperodedenis.py:7482 +msgid "Suppression en cours...." +msgstr "Deleting..." + +#: aperodedenis.py:7487 +msgid "Le précédent chantier %s est en cours de suppression." +msgstr "Previous project %s is being deleted." + +#: aperodedenis.py:7503 +msgid "Repertoires supprimés :" +msgstr "Deleted directories:" + +#: aperodedenis.py:7503 aperodedenis.py:7505 +msgid "Compte rendu de la suppression :" +msgstr "Suppression's log:" + +#: aperodedenis.py:7505 +msgid "Aucun répertoire supprimé." +msgstr "No deleted directory:" + +#: aperodedenis.py:7508 +msgid "Tous les chantiers demandés sont supprimés." +msgstr "All projects asked where deleted." + +#: aperodedenis.py:7510 +msgid "Il reste un chantier impossible à supprimer maintenant : " +msgstr "A project can't be deleted now:" + +#: aperodedenis.py:7512 +msgid "Il reste des chantiers impossibles à supprimer maintenant : " +msgstr "Some projects can't be deleted now:" + +#: aperodedenis.py:7518 +msgid "Choisir" +msgstr "Choose" + +#: aperodedenis.py:7518 +msgid "Choisir : " +msgstr "Choose:" + +#: aperodedenis.py:7588 +msgid " : lancement de " +msgstr " : launching" + +#: aperodedenis.py:7597 +msgid "erreur lors de l'éxécution de la commande :" +msgstr "Error executing command:" + +#: aperodedenis.py:7598 aperodedenis.py:7606 aperodedenis.py:7628 +msgid " : fin de " +msgstr " : ending " + +#: aperodedenis.py:7605 +msgid "erreur lors de l'éxécution de la commande." +msgstr "Error executing command:" + +#: aperodedenis.py:7621 +msgid "erreur lecture output : " +msgstr "Error reading output:" + +#: aperodedenis.py:7643 +msgid "Trace complète" +msgstr "Complete log" + +#: aperodedenis.py:7644 +msgid "Trace synthétique" +msgstr "Synthetic log" + +#: aperodedenis.py:7647 +msgid "Choix des photos :" +msgstr "Pictures choice:" + +#: aperodedenis.py:7648 +msgid "répertoire du chantier :" +msgstr "Project directory:" + +#: aperodedenis.py:7649 +msgid "Version MicMac : " +msgstr "MicMac version: " + +#: aperodedenis.py:7707 +msgid "erreur ecritureTraceMicMac : " +msgstr "ecritureTraceMicMac error:" + +#: aperodedenis.py:7723 +msgid "Choisir une photo" +msgstr "Choose a picture" + +#: aperodedenis.py:7724 +msgid "Cliquer pour choisir une ou plusieurs photos : " +msgstr "Click to select one or several pictures" + +#: aperodedenis.py:7732 +msgid "Pas de photos pour cette demande." +msgstr "No pictures for this request." + +#: aperodedenis.py:7744 +msgid "Dossier corrompu. Traitement interrompu." +msgstr "Corrupted directory. Aborted." + +#: aperodedenis.py:7744 +msgid "Les fichiers suivants sont absents du disque :" +msgstr "Following files are not found:" + +#: aperodedenis.py:7843 +msgid "Options GoPro modifiées" +msgstr "GoPro options edited." + +#: aperodedenis.py:7855 +msgid "Abandon : options GoPro inchangées." +msgstr "Aborted: GoPro option unchanged." + +#: aperodedenis.py:7873 +msgid "" +"L'outil ffmpeg n'est pas installé sur votre ordinateur. Traitement des vidéo " +"GoPro impossible." +msgstr "ffmpeg tool not installet on computer. GoPro video process impossible." + +#: aperodedenis.py:7880 +msgid "" +"Choisir la video issue d'un appareil %(GoProMaker)s %(GoProName)s (sinon " +"modifier les options)" +msgstr "" +"Select a video from a %(GoProMaker)s %(GoProName)s camera (or else edit " +"options)" + +#: aperodedenis.py:7882 +msgid "Video" +msgstr "Video" + +#: aperodedenis.py:7886 +msgid "" +"Abandon, aucune sélection,\n" +" le chantier reste inchangé." +msgstr "Aborting, no selection, project unchanged." + +#: aperodedenis.py:7890 +msgid "" +"La version actuelle ne traite que les videos au format MP4, or le format des " +"photos est %s. Désolé." +msgstr "" +"Current version can only be used with video in .MP4 format. This format is " +"%s. " + +#: aperodedenis.py:7909 +msgid "Décompacte la vidéo" +msgstr "Unpack the video" + +#: aperodedenis.py:7914 +msgid "Il convient de l'associer." +msgstr "It should be associated." + +#: aperodedenis.py:7914 +msgid "L'outil ffmpeg est absent." +msgstr "The ffmpeg tool is missing." + +#: aperodedenis.py:7921 +msgid "Aucune image décompactée : consulter la trace." +msgstr "No picture unpacked: see log for more details." + +#: aperodedenis.py:7948 +msgid "Les images de la video sont décompactées sous le répertoire :" +msgstr "Video's pictures were unpacked in the following directory:" + +#: aperodedenis.py:7949 +msgid "Il y a %s images décompactées." +msgstr "%s pictures unpacked." + +#: aperodedenis.py:7950 +msgid "" +"Lancer 'Sélection des images' pour sélectionner %s images par seconde de " +"film." +msgstr "Launch 'Pictures select' to select %s pictures per second of video." + +#: aperodedenis.py:7951 +msgid "La sélection choisira les 'meilleures' images" +msgstr "The selection will choose the best pictures." + +#: aperodedenis.py:7952 +msgid "" +"Les options Tapioca et Tapas ont été positionnées pour des images GoPro : " +"modifier si besoin" +msgstr "Tapas and Tapioca options are for GoPro pictures: edit if necessary." + +#: aperodedenis.py:7962 +msgid "met à jour l'exif des JPG décompactés :" +msgstr "Update exif from uncompressed JPG:" + +#: aperodedenis.py:7996 +msgid "Cette sélection de photos est réservé aux chantiers vidéos" +msgstr "This pictures selection is for video projects only." + +#: aperodedenis.py:8005 aperodedenis.py:8043 +msgid "Sélection d'un sous ensemble des images GoPro décompactées." +msgstr "Selecting an unpacked pictures subset." + +#: aperodedenis.py:8017 aperodedenis.py:8056 +msgid " a supprimer : " +msgstr "to delete:" + +#: aperodedenis.py:8025 +msgid "" +"Aucune sélection effectuée. La version de micmac ne propose peut-être pas " +"cette fonction." +msgstr "No selection made. The micmac version may not offer this feature." + +#: aperodedenis.py:8025 +msgid "Vous pouvez utiliser le menu 'outils/qualité des photos line'" +msgstr "Use 'Quality of the 'line' pictures' in the Tools menu " + +#: aperodedenis.py:8025 +msgid "puis effectuer une sélection manuelle." +msgstr "then execute a manual selection. " + +#: aperodedenis.py:8025 aperodedenis.py:8064 aperodedenis.py:8385 +#: aperodedenis.py:8521 aperodedenis.py:8539 +msgid "Consulter la trace." +msgstr "Read the log." + +#: aperodedenis.py:8027 aperodedenis.py:8066 +msgid "Images sélectionnées." +msgstr "Selected pictures." + +#: aperodedenis.py:8027 aperodedenis.py:8066 +msgid "Vous pouvez lancer Micmac." +msgstr "You can launch MicMac." + +#: aperodedenis.py:8034 +msgid "Cette sélection de photos est réservé aux chantiers photos" +msgstr "This picture selection is for picture projects only." + +#: aperodedenis.py:8064 +msgid "Aucune sélection effectuée." +msgstr "No selection made." + +#: aperodedenis.py:8064 +msgid "" +"Vous pouvez utiliser le menu 'outils/qualité des photos line'\n" +"puis effectuer une sélection manuelle." +msgstr "" +"Use 'Quality of the 'line' pictures' in the Tools menu \n" +"then execute a manual selection. " + +#: aperodedenis.py:8104 +msgid "Trouvé : " +msgstr "Found:" + +#: aperodedenis.py:8106 +msgid "Non trouvé : " +msgstr "Not found:" + +#: aperodedenis.py:8126 +msgid " Pas de fichier pour " +msgstr "No file for" + +#: aperodedenis.py:8145 +msgid "erreur infobulle : " +msgstr "Tooltip error:" + +#: aperodedenis.py:8192 +msgid "Aucun point placé sur cette photo" +msgstr "No point placed on this picture." + +#: aperodedenis.py:8194 +msgid "Un point placé sur cette photo" +msgstr "One point placed on this picture." + +#: aperodedenis.py:8196 +msgid " points placés sur cette photo" +msgstr "points placed on this picture." + +#: aperodedenis.py:8262 +msgid "Aucun chantier mémorisé." +msgstr "No stored project." + +#: aperodedenis.py:8270 +msgid "Choisir le chantier à ouvrir :" +msgstr "Select a project to open:" + +#: aperodedenis.py:8272 +msgid "vertical" +msgstr "vertical" + +#: aperodedenis.py:8273 +msgid "horizontal" +msgstr "horizontal" + +#: aperodedenis.py:8293 +msgid "Ouvrir" +msgstr "Open" + +#: aperodedenis.py:8298 +msgid " le fichier %s est absent." +msgstr "file %s not found." + +#: aperodedenis.py:8298 +msgid "Il y a des chantiers incomplets," +msgstr "Some projects are incomplete," + +#: aperodedenis.py:8299 +msgid "Ces chantiers ne peuvent être ouverts mais peuvent être supprimés :" +msgstr "These projects can't be opened but can be deleted: " + +#: aperodedenis.py:8324 +msgid "Abandon utilisateur." +msgstr "User abort." + +#: aperodedenis.py:8344 aperodedenis.py:8361 +msgid "HomolTemporaire" +msgstr "HomolTemp" + +#: aperodedenis.py:8346 +msgid "erreur renommage Homol en HomolTemporaire : " +msgstr "Error renaming Homol into HomolTemp" + +#: aperodedenis.py:8351 +msgid "erreur renommage %s en Homol : " +msgstr "Error renaming %s into Homol: " + +#: aperodedenis.py:8359 +msgid "erreur renommage Homol en : %s : " +msgstr "Error renaming Homol into %s:" + +#: aperodedenis.py:8363 +msgid "erreur renommage HomolTemporaire en Homol : " +msgstr "Error renaming HomolTemp into Homol:" + +#: aperodedenis.py:8374 +msgid "dernier traitement : " +msgstr "Last processing: " + +#: aperodedenis.py:8382 +msgid "Lancer MicMac avant de pouvoir évaluer la qualité des photos." +msgstr "Launch MicMac in order to evalutate the quality of the pictures." + +#: aperodedenis.py:8385 +msgid "Le traitement n'a donné aucun point homologue." +msgstr "No tie-point found by processing. " + +#: aperodedenis.py:8423 +msgid "Photo" +msgstr "Picture" + +#: aperodedenis.py:8423 +msgid "nb photos en correspondance" +msgstr "Number of matching pictures" + +#: aperodedenis.py:8423 +msgid "score" +msgstr "score" + +#: aperodedenis.py:8431 +msgid " : fin de la recherche sur la qualité des photos." +msgstr " : end of the pictures quality search." + +#: aperodedenis.py:8447 +msgid "Lancer d'abord Tapioca/Tapas" +msgstr "Launch Tapioca/Tapas in order to go further" + +#: aperodedenis.py:8475 aperodedenis.py:8492 +msgid "Aucun nuage de points dans ce chantier." +msgstr "There is no point cloud in this project." + +#: aperodedenis.py:8478 +msgid "Liste des nuages de points du chantier" +msgstr "Project's point clouds list" + +#: aperodedenis.py:8479 +msgid "les nuages (fichiers ply) :" +msgstr "Clouds (ply files)" + +#: aperodedenis.py:8480 +msgid "Visualiser" +msgstr "Display" + +#: aperodedenis.py:8495 +msgid "Fusion de nuages" +msgstr "Point clouds merge" + +#: aperodedenis.py:8496 +msgid "Choisir les fichiers à fusionner :" +msgstr "Choose files to merge" + +#: aperodedenis.py:8497 +msgid "Fusionner et visualiser" +msgstr "Merge and display" + +#: aperodedenis.py:8503 aperodedenis.py:8518 +msgid "Choisir au moins 2 nuages pour la fusion." +msgstr "Select at least two point clouds to merge." + +#: aperodedenis.py:8521 +msgid "Les ply attendus n'ont pas été créé." +msgstr "The expected ply have not been created." + +#: aperodedenis.py:8536 +msgid "Nuage fusionné :" +msgstr "Point clouds merged: " + +#: aperodedenis.py:8536 +msgid "ajouté à la liste des nuages." +msgstr "Added to point cloud list." + +#: aperodedenis.py:8536 +msgid "résultat de la fusion de :" +msgstr "Merged result from:" + +#: aperodedenis.py:8539 +msgid "La fusion n'a pu se réaliser." +msgstr "The merger could not take place." + +#: aperodedenis.py:8549 aperodedenis.py:8569 aperodedenis.py:8608 +#: aperodedenis.py:8622 aperodedenis.py:8656 +msgid "Saisir une valeur numérique" +msgstr "Enter a digital value" + +#: aperodedenis.py:8555 aperodedenis.py:8575 aperodedenis.py:8628 +msgid "Passage en coordonnées xyz" +msgstr "Passing into xyz coordinates." + +#: aperodedenis.py:8557 aperodedenis.py:8560 aperodedenis.py:8577 +#: aperodedenis.py:8630 +msgid "Création de la grille ..." +msgstr "Creating the grid..." + +#: aperodedenis.py:8585 aperodedenis.py:8635 +msgid "Le calcul peut durer quelques minutes ..." +msgstr "Calculation can take some minutes..." + +#: aperodedenis.py:8591 +msgid "Rugosité moyenne quadratique : " +msgstr "Medium quadratic roughness:" + +#: aperodedenis.py:8592 +msgid "Tortuosité moyenne : " +msgstr "average tortuosity:" + +#: aperodedenis.py:8593 aperodedenis.py:8641 +msgid "nombre de profils utilisés : " +msgstr "Number of profiles used: " + +#: aperodedenis.py:8594 aperodedenis.py:8603 aperodedenis.py:8610 +#: aperodedenis.py:8642 aperodedenis.py:8651 aperodedenis.py:8658 +msgid "id profil entre : " +msgstr "Id of the entered profile: " + +#: aperodedenis.py:8602 aperodedenis.py:8650 +msgid "Choisir une valeur valide " +msgstr "Choose a valid value" + +#: aperodedenis.py:8639 +msgid "Profondeur moyenne de profil (moyenne) : " +msgstr "average depth profile :" + +#: aperodedenis.py:8640 +msgid "Profondeur de texture équivalente : " +msgstr "Equivalent depth of texture :" + +#: aperodedenis.py:8668 +msgid "Le programme de conversion n'est pas présent." +msgstr "The conversion program is not present." + +#: aperodedenis.py:8694 +msgid "Paramètres mis à jour" +msgstr "Settings updated" + +#: aperodedenis.py:8695 +msgid "Méthode = " +msgstr "Method = " + +#: aperodedenis.py:8696 +msgid "Pas du maillage = " +msgstr "Mesh range = " + +#: aperodedenis.py:8743 +msgid "Exifs mis à jour" +msgstr "Exifs updated" + +#: aperodedenis.py:8744 +msgid "Fabricant = " +msgstr "Manufacturer =" + +#: aperodedenis.py:8745 +msgid "Modèle = " +msgstr "Model =" + +#: aperodedenis.py:8746 +msgid "Focale = " +msgstr "Focal length =" + +#: aperodedenis.py:8747 +msgid "Focale eq 35mm = " +msgstr "Focal length eq 35mm =" + +#: aperodedenis.py:8751 +msgid "Abandon de la mise à jour des exifs" +msgstr "Exif update aborted." + +#: aperodedenis.py:8761 +msgid "Aucune photo à mettre à jour." +msgstr "No picture to update." + +#: aperodedenis.py:8764 +msgid "" +"La liste des fichiers comporte plusieurs extensions différentes : abandon." +msgstr "These files include several different extensions: aborting." + +#: aperodedenis.py:8769 +msgid "" +"La version actuelle ne traite que les exif des photos au format JPG, or le " +"format des photos est %s. Désolé, abandon." +msgstr "" +"Current version can only process exif in JPG format, these pictures format " +"is %s. Aborting." + +#: aperodedenis.py:8775 +msgid "Le fichier %s n'existe pas. Abandon" +msgstr "%s file doesn't exists. Abort." + +#: aperodedenis.py:8779 +msgid "met à jour l'exif de " +msgstr "Update exif of" + +#: aperodedenis.py:8805 +msgid "Choisir des photos au préalable." +msgstr "Choose pictures beforehand." + +#: aperodedenis.py:8809 +msgid "Attention les photos suivantes sont absentes sur disque : " +msgstr "Warning, some pictures are missing on the disk:" + +#: aperodedenis.py:8809 +msgid "Elles sont supprimées." +msgstr "They've been deleted." + +#: aperodedenis.py:8814 +msgid "Problème de fichiers" +msgstr "Files problem" + +#: aperodedenis.py:8818 +msgid "Bonjour !" +msgstr "Hello !" + +#: aperodedenis.py:8818 +msgid "Commencer par indiquer où se trouve MicMac :" +msgstr "Start by selecting the MicMac's directory:" + +#: aperodedenis.py:8819 +msgid " - menu Paramétrage/Associer le répertoire bin de MicMac" +msgstr "- Settings menu/link the MicMac\\bin directory." + +#: aperodedenis.py:8820 +msgid "Ensuite consulter l'aide, item 'pour commencer'." +msgstr "Next, read \"Get started\" in the Help menu." + +#: aperodedenis.py:8821 +msgid "Si besoin :" +msgstr "if necessary:" + +#: aperodedenis.py:8822 +msgid "" +" - Associer convert et exiftool s'ils ne sont pas trouvés automatiquement " +"sous micmac/binaire-aux" +msgstr "" +"- Link the convert and exiftool directories if they're not in micmac/binaire-" +"aux directory." + +#: aperodedenis.py:8823 +msgid "" +" - Associer un outil (CloudCompare ou Meshlab) pour afficher les nuages de " +"points 3D" +msgstr "- Link a tool (CloudCompare or Meslab) to display 3D point clouds." + +#: aperodedenis.py:8824 +msgid " - Consulter la notice d'installation et de prise en main" +msgstr "- Read installation and grip instructions" + +#: aperodedenis.py:8835 +msgid "Désigner le fichier convert, ou avconv, d'image Magick" +msgstr "Designate the convert or avconv file from ImageMagick " + +#: aperodedenis.py:8835 +msgid "en principe sous micmac\\binaire-aux (menu paramétrage)." +msgstr "usually in micmac\\binaire-aux (Settings menu)." + +#: aperodedenis.py:8840 +msgid "" +"Désigner le fichier ffmpeg (possible sous micmac\\binaire-aux (menu " +"paramétrage)." +msgstr "Designate the file ffmpeg." + +#: aperodedenis.py:8857 +msgid "Revenir aux options par défaut d'AperoDeDenis" +msgstr "Return to default AperoDeDenis's options." + +#: aperodedenis.py:8858 aperodedenis.py:8876 +msgid "Utiliser les options du chantier en cours" +msgstr "Use current project's options." + +#: aperodedenis.py:8859 aperodedenis.py:8877 +msgid "Ne rien changer" +msgstr "Don't change anything." + +#: aperodedenis.py:8862 +msgid "Options par défaut réinitialisées" +msgstr "Default options reset." + +#: aperodedenis.py:8866 aperodedenis.py:8881 +msgid "Les options par défaut seront désormais celles du chantier en cours" +msgstr "Default options are now current project's options." + +#: aperodedenis.py:8875 +msgid "" +"Les options par défaut actuelles sont les options par défaut d'AperoDeDenis" +msgstr "Current default options are AperoDeDenis's default options." + +#: aperodedenis.py:8890 +msgid "" +"Options par défaut non sauvegardées car les options du chantier en cours " +"sont invalides :" +msgstr "Project options not valid, default options remain unchanged:" + +#: aperodedenis.py:8916 +msgid "erreur sauveOptions : " +msgstr "Error sauveOptions:" + +#: aperodedenis.py:8917 +msgid "Erreur rencontrée lors de la sauvegarde des options : " +msgstr "Encountered error when saving options:" + +#: aperodedenis.py:8946 +msgid "erreur restauration options : " +msgstr "Error loading options:" + +#: aperodedenis.py:8985 +msgid "fin normale d'aperodedenis." +msgstr "Normal end of AperoDeDenis" + +#: aperodedenis.py:9003 +msgid "fonction" +msgstr "function" + +#: aperodedenis.py:9004 +msgid "valeur en retour : " +msgstr "Return value:" + +#: aperodedenis.py:9007 +msgid "variable" +msgstr "variable" + +#: aperodedenis.py:9008 +msgid "valeur : " +msgstr "valor:" + +#: aperodedenis.py:9009 +msgid "Détail de la %(typeVar)s : %(nomVar)s" +msgstr "%(typeVar)s détails: %(nomVar)s" + +#: aperodedenis.py:9010 +msgid "Identifiant : " +msgstr "Identifier:" + +#: aperodedenis.py:9011 +msgid "Type : " +msgstr "Type:" + +#: aperodedenis.py:9012 +msgid "class = " +msgstr "class =" + +#: aperodedenis.py:9013 +msgid "Les attributs : " +msgstr "Attributes:" + +#: aperodedenis.py:9021 +msgid "Erreur suppression fichier :" +msgstr "Error deleting file:" + +#: aperodedenis.py:9044 +msgid "erreur ajout : " +msgstr "Add error:" + +#: aperodedenis.py:9059 +msgid "erreur remove = " +msgstr "Remove error:" + +#: aperodedenis.py:9085 +msgid "erreur zip = " +msgstr "Zip error:" + +#: aperodedenis.py:9117 +msgid "erreur mercurial : %(e)s pour mm3D=%(mm3D)s" +msgstr "Mercurial error: %(e)s for mm3d=%(mm3D)s" + +#: aperodedenis.py:9118 +msgid "pas de version identifiée de MicMac" +msgstr "Not know MicMac's version" + +#: aperodedenis.py:9167 +msgid "Nouveau nom pour le chantier : " +msgstr "New project's name:" + +#: aperodedenis.py:9203 +msgid "Console" +msgstr "Console" + +#: aperodedenis.py:9320 +msgid "Question" +msgstr "Question" + +#~ msgid "Nouvelle version : " +#~ msgstr "New version: " + +#~ msgid "Ortho pour orthophotos" +#~ msgstr "Ortho for orthophotos" + +#~ msgid "Liste des images maîtresses et des masques" +#~ msgstr "Master pictures and masks list" + +#~ msgid "Photo utile pour malt AperoDeDenis : " +#~ msgstr "Photo useful for malt AperoDeDenis:" + +#~ msgid "Supprimer tous les points" +#~ msgstr "Remove all points" + +#~ msgid "Nombre de photos utiles en + et en - autour de l'image maitresse :" +#~ msgstr "Number of useful pictures in more or less around master picture" + +#~ msgid "2 fois %s photos utiles autour de la maîtresse" +#~ msgstr "2 times %s useful pictures around master picture." + +#~ msgid "Attention : chaque points doit être sur 2 photos au moins." +#~ msgstr "Warning: each points must be placed on at least two pictures." + +#~ msgid "Saisie incomplète : les points ne seront pas pris en compte" +#~ msgstr "Incomplete entry : points will no be considered." + +#~ msgid "Il est mis à 1." +#~ msgstr "It was put to 1." + +#~ msgid "Nombre de photos autour de la maîtresse : " +#~ msgstr "Number of pictures around the master picture:" + +#~ msgid " photos traitées par Malt :" +#~ msgstr " pictures processed by Malt: " + +#~ msgid "Erreur lors de la recherche des photos proches de la maitresse %s." +#~ msgstr "Error searching pictures like master picture %s. " + +#~ msgid "Toutes les photos sont conservées." +#~ msgstr "All pictures are preserved." + +#~ msgid "erreur verifier si executable : " +#~ msgstr "Error, check executable:" + +#~ msgid "" +#~ "Chantier modifé depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?" +#~ msgstr "" +#~ "The project has been edited since last save. Do you want to save it?" + +#~ msgid "ATTENTION : FERMER la fenêtre 3D pour continuer" +#~ msgstr "Warning: close 3D window ton continue" + +#~ msgid "Pas de distance définie pour ce chantier." +#~ msgstr "No distance defined for this project." + +#~ msgid "Sélectionnez la langue à utiliser. L'application sera redémarée." +#~ msgstr "Select the language. The application wil be relaunched." + +#~ msgid "avant" +#~ msgstr "before" + +#~ msgid "aprés =" +#~ msgstr "after =" + +#~ msgid "Nombre de photos retenues : " +#~ msgstr "Number of choosen pictures" + +#~ msgid "" +#~ " les photos ayant un mauvais score (voir le menu Outils/" +#~ "Qualité des photos 'All') doivent être supprimées du chantier : elle " +#~ "peuvent faire échouer le traitement." +#~ msgstr "" +#~ " Pictures with a bad score (see : Tools/Pictures quality " +#~ "'All' menu) must be deleted from the project : they can make the process " +#~ "fail." + +#~ msgid "Il convient de l'ajouter." +#~ msgstr "You should add it." + +#~ msgid "L'outil ffmpeg est absent du répertoire %s." +#~ msgstr "ffmpeg tool absent from %s" + +#~ msgid "" +#~ "Désigner le fichier ffmpeg en principe sous micmac\\binaire-aux (menu " +#~ "paramétrage)." +#~ msgstr "" +#~ "Designate the ffmpeg file, normally in micmac\\binaire-aux (Settings " +#~ "menu)." + +#~ msgid "Points GPS vérifiés par controlePoints : non conformes. Vérifiez." +#~ msgstr "GPS pointes checkec by controlePoints: improper. Check." + +#~ msgid "Points GPS non conformes. Vérifiez." +#~ msgstr "GPS points improper. Check." + +#~ msgid "le %(jour)s/%(mois)s/%(annee)s à %(heure)s:%(minutes)s:%(secondes)s" +#~ msgstr "" +#~ "On %(jour)s/%(mois)s/%(annee)s at %(heure)s:%(minutes)s:%(secondes)s" + +#~ msgid "AperoDeDenis est déjà lancé dans la fenêtre :" +#~ msgstr "AperoDeDenis is already launched in: " + +#~ msgid "" +#~ "La version actuelle d'AperoDeDenis n'autorise qu'une seule instance du " +#~ "programme." +#~ msgstr "" +#~ "This version of AperoDeDenis allow only one instance of the program." + +#~ msgid "Valider pour quitter." +#~ msgstr "Confirm to exit" + +#~ msgid "AperoDeDenis : avertissement" +#~ msgstr "AperoDeDenis : warning" + +#~ msgid "test bilingue new" +#~ msgstr "traduction bidon" + +#~ msgid "" +#~ "Erreur lors du décodage des données, le ply ne proviient pas de micmac. " +#~ "Erreur : " +#~ msgstr "" +#~ "Error when decoding the datas, the ply file is not from MicMac. Error: " + +#~ msgid " : Une interface graphique pour MicMac..." +#~ msgstr ": a MicMac's graphic user interface..." + +#~ msgid "Nouveau chantier : Choisir une video GoPro, ou autre" +#~ msgstr "New project: select a goPro video, or else" + +#~ msgid "Nom de la camera GoPRo : " +#~ msgstr "Name of the camera:" + +#~ msgid "Info : Format des photos" +#~ msgstr "Info: pictures format" + +#~ msgid "" +#~ "ATTENTION : Des points GPS ont été précedemment placés sur des photos non " +#~ "choisies pour ce chantier." +#~ msgstr "" +#~ "Warning: some pictures on which GPS points were previously placed were " +#~ "not choosen for the project." + +#~ msgid "" +#~ "Attention : Il faut au moins 3 points pour qu'ils soient pris en compte." +#~ msgstr "Warning: at least three points needed to take them into account." + +#~ msgid "Attention : Des points portent le même nom : corriger !" +#~ msgstr "Warning: some points have the same name : correct it !" + +#~ msgid "" +#~ "ATTENTION : Des Metadonnées nécessaires sont absentes des photos. " +#~ "Vérifier l'exif." +#~ msgstr "" +#~ "Warning: required metadatas are absent from pictures. Check the exif." + +#~ msgid " : Voir la trace complète." +#~ msgstr ": see complete log." + +#~ msgid "" +#~ " - Du ménage ! : Supprimer les chantiers : Chaque chantier crée une " +#~ "arborescence de travail." +#~ msgstr "" +#~ " - Let's clean !: delete projects: each project create a work tree." + +#~ msgid "" +#~ " - Tapas : Choix d'un mode de calcul, possibilité " +#~ "d'arrêter le traitement après tapas." +#~ msgstr "" +#~ " - Tapas: choice of a calculation mode, allow to stop " +#~ "processing after Tapas." + +#~ msgid "" +#~ " - GPS : Définir les points de calage GPS qui " +#~ "permettent de géolocaliser la scène." +#~ msgstr "" +#~ " -GPS: define GPS points allowing to geolocate the " +#~ "scene." + +#~ msgid "" +#~ " - GPS : Définir les points de calage GPS qui " +#~ "permettent de géolocaliser la scène." +#~ msgstr "" +#~ " - GPS: define GPS points that allows to geo-locate " +#~ "the scene." + +#~ msgid "" +#~ " - Lancer MicMac : Enregistre le chantier et lance le traitement " +#~ "avec les options par défaut ou choisies par l'item 'options'." +#~ msgstr "" +#~ "- Launch MicMac: save project and start processing with current options." + +#~ msgid "" +#~ " Attention : Cette étape n'est pas effective pour toutes les " +#~ "versions de MicMac. La version mercurial 5508 fonctionne." +#~ msgstr "" +#~ " Warning: this step does not work in all versions of MicMac. The " +#~ "mercurial 5508 version works." + +#~ msgid "" +#~ " les photos ayant un mauvais score doivent être " +#~ "supprimées du chantier : elle peuvent faire échouer le traitement." +#~ msgstr "" +#~ " Pictures with bad scores (See the Tools/Check quality " +#~ "of the pictures menu) must be deleted: these can make the process fails." + +#~ msgid "" +#~ " - Tapioca : Si le sujet est central conserver les " +#~ "paramètres par défaut." +#~ msgstr "" +#~ " - Tapioca: if the subject is in the center, keep the " +#~ "default settings." + +#~ msgid "" +#~ " - Tapas : Si l'appareil photo est un compact ou un " +#~ "smartphone choisir RadialBasic, " +#~ msgstr "" +#~ " - Tapas: if the camera is compact or a smartphone, choose " +#~ "RadialBasic," + +#~ msgid "" +#~ " Si l'appareil photo est un reflex haut de gamme " +#~ "choisir RadialExtended " +#~ msgstr "" +#~ " If the camera is a top of the line reflex, " +#~ "choose RadialExtended" + +#~ msgid "" +#~ " Si l'appareil photo est de moyenne gamme choisir " +#~ "RadialStd" +#~ msgstr "" +#~ " If it's an average line camera, choose RadialStd" + +#~ msgid "" +#~ " Si les photos ont 2 focales alors choisir toutes " +#~ "celles qui ont la plus grande focale pour la calibration intrinsèque." +#~ msgstr "" +#~ " If pictures have two focal length, choose those " +#~ "which have a bigger focal length for intrinsic calibration." + +#~ msgid " Tout d'abord : Installer MicMac." +#~ msgstr " First of all: install MicMac" + +#~ msgid "" +#~ " Puis : Installer Meshlab ou CloudCompare (pour afficher les nuages de " +#~ "points)" +#~ msgstr " Then: install MeshLab or CloudCompare (to display point clouds)" + +#~ msgid "" +#~ "Version 1.55 : Sous Windows le fichier paramètre est placé sous le " +#~ "répertoire APPDATA de l'utilisateur," +#~ msgstr "Version 1.55:" + +#~ msgid "Version 1.60 : Ajout des fonctions :" +#~ msgstr "Version 1.60: functions added" + +#~ msgid "Version 2.00 : Ajout des fonctions :" +#~ msgstr "Version 2.00: functions added:" + +#~ msgid " : Lancement de " +#~ msgstr ": launching" + +#~ msgid " : Fin de " +#~ msgstr ": ending" + +#~ msgid " : Fin de la recherche sur la qualité des photos." +#~ msgstr ": search about picture quality has ended." + +#~ msgid "AperoDeDenis : Avertissement" +#~ msgstr "AperoDeDenis: warning" + +#~ msgid "photos" +#~ msgstr "pictures" + +#~ msgid "initial" +#~ msgstr "initial" + +#~ msgid "original" +#~ msgstr "original" + +#~ msgid "renommé" +#~ msgstr "renamed" + +#~ msgid "importé" +#~ msgstr "imported" + +#~ msgid "vidéo" +#~ msgstr "video" + +#~ msgid "le nuage est en cours de calibration." +#~ msgstr "Calibrating cloud..." + +#~ msgid "" +#~ " N'utiliser ces photos que pour la calibration\n" +#~ " (exemple : focales différentes)" +#~ msgstr "" +#~ "Use these picture for the calibration only \n" +#~ "(example : différents focal lenghts)" + +#~ msgid "" +#~ "Toutes ces photos doivent avoir la même focale,\n" +#~ "éventuellement différente de la focale des autres photos." +#~ msgstr "" +#~ "Every of theses pictures must have the same focal lenght,\n" +#~ "but can have a different focal lenght than the other pictures." + +#~ msgid "" +#~ "Attention : Le masque 3D de C3DC a la priorité sur Malt\n" +#~ "Pour supprimer un masque : supprimer la maitresse" +#~ msgstr "" +#~ "Warning : 3D mask from C3DC has priority over Malt.\n" +#~ "To delete a mask, delete the master picture." + +#~ msgid "" +#~ "Modification des Exif\n" +#~ "\n" +#~ "Marque de l'appareil : " +#~ msgstr "" +#~ "Exif edit\n" +#~ "\n" +#~ "Brand of the camera :" + +#~ msgid "" +#~ "Le renommage du chantier ne peut se faire actuellement,\n" +#~ "soit le nom fourni est incorrect," +#~ msgstr "" +#~ "Can't rename project now,\n" +#~ "either the name is incorrect," + +#~ msgid "" +#~ "%(heure)s\n" +#~ "Chantier :\n" +#~ "%(ancien)s\n" +#~ "renommé en :\n" +#~ "%(chantier)s\n" +#~ "Répertoire : %(rep)s" +#~ msgstr "" +#~ "%(heure)\n" +#~ " Project : \n" +#~ "%(ancien)s \n" +#~ "renamed into : \n" +#~ "%(chantier)s \n" +#~ "Directory : %(rep)s" + +#~ msgid "" +#~ "Archive \n" +#~ "%(nomChantier)s.exp\n" +#~ " créée sous \n" +#~ "%(rep)s\n" +#~ "\n" +#~ " Taille = %(str)s KO." +#~ msgstr "" +#~ "Archive \n" +#~ "%(nomChantier)s.exp \n" +#~ "created in \n" +#~ "%(rep)s \n" +#~ "\n" +#~ "Size = %(str)s Ko." + +#~ msgid "" +#~ "Recopie en cours dans\n" +#~ "%s\n" +#~ "Patience !" +#~ msgstr "" +#~ "Copying in \n" +#~ "%s. \n" +#~ "Please wait." + +#~ msgid "" +#~ "Le répertoire destination\n" +#~ "%s\n" +#~ "existe déjà. Abandon" +#~ msgstr "Destination directory %s already exist. Aborting." + +#~ msgid "" +#~ "Erreur lors de la copie du fichier paramètre chantier \n" +#~ "%(param)s\n" +#~ " vers \n" +#~ "%(rep)s\n" +#~ " erreur :" +#~ msgstr "" +#~ "Error when copying project settings file : \n" +#~ "%(param)s \n" +#~ "to \n" +#~ "%(rep)s \n" +#~ "error :" + +#~ msgid "" +#~ "%(entete)s\n" +#~ "Répertoire de la vidéo : \n" +#~ "%(chem)s" +#~ msgstr "" +#~ "%(entete)s \n" +#~ "Video directory : \n" +#~ "%(chem)s" + +#~ msgid "" +#~ " photos sélectionnées\n" +#~ "(sans calibration si tapas executé) : " +#~ msgstr "" +#~ "pictures selected\n" +#~ "(without calibration if Tapas executed)" + +#~ msgid "" +#~ "Les caractéristiques du chantier précédent \n" +#~ "%s\n" +#~ " n'ont pas pu être lues correctement." +#~ msgstr "" +#~ "Characteristics from last project \n" +#~ "%s \n" +#~ "couldn't be read properly." + +#~ msgid "" +#~ "Toutes les photos\n" +#~ "sans les %s photos pour calibration intrinseque" +#~ msgstr "" +#~ "All pictures \n" +#~ "without %s pictures for intrinsic calibration." + +#~ msgid "" +#~ "Abandon, pas de changement.\n" +#~ "Répertoire bin de Micmac :" +#~ msgstr "" +#~ "Abort, no change. \n" +#~ "Directory of MicMac\\bin :" + +#~ msgid "" +#~ "Répertoire bin sous MicMac incorrect. \n" +#~ "Abandon." +#~ msgstr "" +#~ "Wrong directory for MicMac\\bin. \n" +#~ "Aborting." + +#~ msgid "" +#~ "Abandon, pas de changement.\n" +#~ "Fichier exiftool inchangé :" +#~ msgstr "" +#~ "Aborting, no change. \n" +#~ "Exiftool file unchanged." + +#~ msgid "" +#~ "Abandon, pas de changement.\n" +#~ "Fichier convert inchangé :" +#~ msgstr "" +#~ "Aborting, no change. \n" +#~ "Convert file unchanged." + +#~ msgid "" +#~ "Abandon, pas de changement.\n" +#~ "Fichier Meshlab ou cloud compare :" +#~ msgstr "" +#~ "Aborting, no change. \n" +#~ "Meshlab or CloudCompare file :" + +#~ msgid "" +#~ "Abandon, pas de changement.\n" +#~ "Fichier ffmpeg inchangé :" +#~ msgstr "" +#~ "Aborting, no change. \n" +#~ "ffmpeg file unchanged." + +#~ msgid "" +#~ "Abandon, aucune sélection de fichier image,\n" +#~ " le répertoire et les photos restent inchangés." +#~ msgstr "" +#~ "Aborting, no picture file selected, \n" +#~ "directory and pictures unchanged." + +#~ msgid "" +#~ "La version actuelle ne traite que les photos au format JPG,\n" +#~ "\n" +#~ " or le format des photos est : " +#~ msgstr "" +#~ "The current version can only process JPG files,\n" +#~ "\n" +#~ "but these pictures format is :" + +#~ msgid "" +#~ "Désigner l'outil de conversation 'convert' d'ImageMagick\n" +#~ "(Menu Paramétrage)" +#~ msgstr "" +#~ "Designate the ImageMagick's convert conversation tool. \n" +#~ "(Settings menu)" + +#~ msgid "" +#~ "Impossible de créer le répertoire de travail.\n" +#~ "Vérifier les droits en écriture sous le répertoire des photos" +#~ msgstr "" +#~ "Impossible to create working directory. \n" +#~ "Please check write permission on the pictures directory." + +#~ msgid "" +#~ "Aucun JPG, PNG, BMP, TIF, ou GIF sélectionné,\n" +#~ "le répertoire et les photos restent inchangés." +#~ msgstr "" +#~ "No JPG, PNG, BMP, TIF or GIF selected, \n" +#~ "pictures and directories unchanged." + +#~ msgid "" +#~ "L'outil exiftool n'est pas localisé : controle des photos impossible.\n" +#~ "Désigner le fichier exiftool (menu paramétrage)." +#~ msgstr "" +#~ "Exiftool not found : controlling pictures is impossible. \n" +#~ "Please show exiftool file (Settings menu)" + +#~ msgid "" +#~ "Les focales sont absentes des exif.\n" +#~ "Mettez à jour les exifs avant de lancer MicMac." +#~ msgstr "" +#~ "Focal lenght absent from exif. \n" +#~ "Please update exifs before launching MicMac." + +#~ msgid "" +#~ "erreur lors de la copie du fichier\n" +#~ "%(x)s\n" +#~ " dans le répertoire \n" +#~ "%(y)s\n" +#~ "libellé de l'erreur : \n" +#~ "%(z)s\n" +#~ "Causes possibles : manque d'espace disque ou droits insuffisants." +#~ msgstr "" +#~ "Error when copying \n" +#~ "%(x)s file\n" +#~ "in the \n" +#~ "%(y)s directory.\n" +#~ "Error :\n" +#~ "%(z)s \n" +#~ "Possibles causes : no enough space or you don't have permissions." + +#~ msgid "" +#~ "pas de fichier AperiCloud.ply pour construire le masque :\n" +#~ "lancer Micmac pour en constituer un." +#~ msgstr "" +#~ "No AperiCloud.ply file to build the mask : \n" +#~ "launch MicMac to generate one." + +#~ msgid "" +#~ "L'échelle 2 de MulScale pour tapioca\n" +#~ "%(x)s\n" +#~ " plus petite que l'échelle 1 : \n" +#~ "%(y)s" +#~ msgstr "" +#~ "Scale 2 of Tapioca's MulScale \n" +#~ "%(x)s \n" +#~ "is smaller than scale 1 : \n" +#~ "%(y)s" + +#~ msgid "" +#~ "La valeur de delta pour le mode Line de Tapioca est invalide,\n" +#~ " une valeur par défaut, %s, est affectée." +#~ msgstr "" +#~ "Delta value from Tapioca's Line is invalid, \n" +#~ "a default value, %s, is affected. " + +#~ msgid "" +#~ "L'échelle pour le mode All de tapioca = %(x)s\n" +#~ ", est plus grande que la dimension maxi de la photo : " +#~ msgstr "" +#~ "Scale for Tapioca's All mode = %(x)s, \n" +#~ "is bigger than pictures maximum dimension." + +#~ msgid "" +#~ "L'échelle 2 pour le mode MulScale de tapioca= %(x)s\n" +#~ " est plus grande que la dimension maxi de la photo :" +#~ msgstr "" +#~ "Scale 2 Tapioca's MulScale mode = %(x)s, \n" +#~ "is bigger than pictures maximum dimension." + +#~ msgid "" +#~ "L'échelle pour le mode Line de tapioca = %(x)s\n" +#~ " est plus grande que la dimension maxi de la photo :" +#~ msgstr "" +#~ "Scale for Tapioca's Line mode = %(x)s, \n" +#~ "is bigger than pictures maximum dimension." + +#~ msgid "" +#~ "Quelques photos, convergentes, d'angles écartés\n" +#~ "en jaune la calibration actuelle" +#~ msgstr "" +#~ "Some pictures, convergent, apart from angles\n" +#~ "in yellow, the current calibration." + +#~ msgid "" +#~ "Choisir une ou plusieurs image(s) maîtresse(s)\n" +#~ "en jaune : les maitresses actuelles\n" +#~ "Une info bulle informe de la présence d'un masque" +#~ msgstr "" +#~ "Select one or several master pictures. \n" +#~ "Current master pictures are in yellow.\n" +#~ "A tooltip informs of the presence of a mask. " + +#~ msgid "" +#~ "Appliquer au \n" +#~ "nuage non densifié" +#~ msgstr "" +#~ "Aplly on\n" +#~ "not densified point cloud" + +#~ msgid "" +#~ "Agrandissez la fenêtre avant d'ajouter un point GPS !\n" +#~ "(ou si impossible : supprimer un point)" +#~ msgstr "" +#~ "Extend the window before adding a GPS point !\n" +#~ "(or if impossible : remove a point)" + +#~ msgid "" +#~ "Lancer d'abord tapioca/tapas\n" +#~ "pour obtenir un nuage non densifié." +#~ msgstr "" +#~ "Launch Tapioca/Tapas first\n" +#~ "to obtain a not densified point cloud." + +#~ msgid "" +#~ "Avec 2 photos MicMac construira difficilement un nuage de point dense.\n" +#~ "Utiliser l'échelle -1 dans Tapioca pour obtenir un nuage optimal." +#~ msgstr "" +#~ "With two pictures, MicMac will build a densified point cloud with " +#~ "difficulty.\n" +#~ "Use scale -1 in Tapioca to obtain an optimal cloud." + +#~ msgid "" +#~ "Le chantier est interrompu.\n" +#~ "Vous pouvez le débloquer," +#~ msgstr "" +#~ "Project interrupted. \n" +#~ "You can unblock it," + +#~ msgid "" +#~ "Consulter l'aide (quelques conseils),\n" +#~ "consulter la trace." +#~ msgstr "" +#~ "See Help (advices), \n" +#~ "see the log." + +#~ msgid "" +#~ "Calibration intrinsèque, pour trouver les réglages de l'appareil photo " +#~ "sur quelques photos\n" +#~ "Recherche d'un point de convergence au centre de l'image." +#~ msgstr "" +#~ "Intrinsic calibration, to find camera settings on some pictures.\n" +#~ "Searching for a convergence points in the picture center." + +#~ msgid "" +#~ "Calibration, pour trouver les réglages intrinsèques de l'appareil photo\n" +#~ "Recherche l'orientation des prises de vue." +#~ msgstr "" +#~ "Calibration, to find intrinsic settings of the camera\n" +#~ "Searching for shooting orientation." + +#~ msgid "" +#~ "Positionne les appareils photos autour du sujet.\n" +#~ "\\Création d'un nuage de points grossier." +#~ msgstr "" +#~ "Set cameras around the subject.\n" +#~ "Creating rough point cloud." + +#~ msgid "" +#~ "Erreur lors de la recherche des photos proches de la maitresse %s.\n" +#~ "Toutes les photos sont conservées." +#~ msgstr "" +#~ "Error searching pictures like master picture %s. \n" +#~ "All pictures are preserved." + +#~ msgid "" +#~ "Le résultat sera inscrit dans le fichier trace synthétique\n" +#~ "\n" +#~ "Patience..." +#~ msgstr "" +#~ "The result will be written in the synthetic log file. \n" +#~ "\n" +#~ "Please wait..." + +#~ msgid "" +#~ "Il y a des chantiers incomplets,\n" +#~ " le fichier %s est absent." +#~ msgstr "" +#~ "Some projects are incomplete,\n" +#~ "file %s not found." + +#~ msgid "" +#~ "Le traitement n'a donné aucun point homologue.\n" +#~ "\n" +#~ "Consulter la trace." +#~ msgstr "" +#~ "No homologous point found by processing. \n" +#~ "\n" +#~ "Please read the log." + +#~ msgid "" +#~ "Désigner le fichier ffmpeg en principe sous micmac\\010inaire-aux (menu " +#~ "paramétrage)." +#~ msgstr "" +#~ "Select the ffmpeg file, probably in micmac\\binaire-aux (settings menu)." + +#~ msgid "" +#~ "%(entete)s\n" +#~ "Répertoire des photos : \n" +#~ "%(chem)s" +#~ msgstr "" +#~ "%(entete)s \n" +#~ "Pictures directory : \n" +#~ "%(chem)s" + +#~ msgid "" +#~ "Désigner le fichier convert, ou avconv, d'image Magick\n" +#~ "en principe sous micmac\\010inaire-aux (menu paramétrage)." +#~ msgstr "" +#~ "Select the convert file, or avconv, of Image Magick\n" +#~ "probably in micmac\\binaire-aux (settings menu)" + +#~ msgid "essai" +#~ msgstr "try" diff --git a/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.mo b/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.mo new file mode 100644 index 0000000..a6882ce Binary files /dev/null and b/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.mo differ diff --git a/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.po b/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.po new file mode 100644 index 0000000..ce05aeb --- /dev/null +++ b/InterfaceCEREMA/locale/fr/LC_MESSAGES/AperoDeDenis.po @@ -0,0 +1,5599 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2017-01-26 11:04+0100\n" +"PO-Revision-Date: 2017-01-26 11:04+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 1.8.11\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: aperodedenis.py:270 +msgid " lancement d'aperodedenis" +msgstr "" + +#: aperodedenis.py:287 aperodedenis.py:2656 aperodedenis.py:3332 +#: aperodedenis.py:3353 aperodedenis.py:3373 aperodedenis.py:3394 +#: aperodedenis.py:3479 aperodedenis.py:7800 +msgid "Tous" +msgstr "" + +#: aperodedenis.py:288 +msgid "Ply à lire" +msgstr "" + +#: aperodedenis.py:291 +msgid "Fichier à lire : " +msgstr "" + +#: aperodedenis.py:297 +msgid "Il ne s'agit pas d'un fichier ply issu de MicMac !" +msgstr "" + +#: aperodedenis.py:300 +msgid "Fichier à écrire : " +msgstr "" + +#: aperodedenis.py:312 +msgid "nombre de points : " +msgstr "" + +#: aperodedenis.py:323 +msgid " le format attendu est : fffBBB" +msgstr "" + +#: aperodedenis.py:323 +msgid "" +"Le format des données indique qu'il ne s'agit pas d'un ply généré par " +"MicMac. Le format trouvé est : " +msgstr "" + +#: aperodedenis.py:326 +msgid "Longueur du fichier : " +msgstr "" + +#: aperodedenis.py:327 +msgid "format du fichier > = big_endian, < = little_endian :" +msgstr "" + +#: aperodedenis.py:328 +msgid " longueur : " +msgstr "" + +#: aperodedenis.py:328 +msgid "Format des données : " +msgstr "" + +#: aperodedenis.py:330 +msgid "patience : écriture du fichier xyz en cours" +msgstr "" + +#: aperodedenis.py:335 +msgid " fin = " +msgstr "" + +#: aperodedenis.py:335 +msgid " longueur = " +msgstr "" + +#: aperodedenis.py:335 +msgid "Plage des données : début = " +msgstr "" + +#: aperodedenis.py:339 +msgid "" +"Erreur lors du décodage des données, le ply ne provient pas de micmac. " +"Erreur : " +msgstr "" + +#: aperodedenis.py:354 aperodedenis.py:423 +msgid "nom du fichier contenant les données : à déterminer" +msgstr "" + +#: aperodedenis.py:403 +msgid " pas du maillaige : " +msgstr "" + +#: aperodedenis.py:546 +msgid "profil n°" +msgstr "" + +#: aperodedenis.py:558 +msgid "Tracer le masque" +msgstr "" + +#: aperodedenis.py:560 +msgid "Saisie sur la photo : " +msgstr "" + +#: aperodedenis.py:609 +msgid "Inverser" +msgstr "" + +#: aperodedenis.py:610 aperodedenis.py:922 +msgid "Valider" +msgstr "" + +#: aperodedenis.py:611 aperodedenis.py:925 aperodedenis.py:3467 +#: aperodedenis.py:5087 aperodedenis.py:5113 aperodedenis.py:5124 +#: aperodedenis.py:5135 aperodedenis.py:5151 aperodedenis.py:5172 +#: aperodedenis.py:6259 aperodedenis.py:8168 aperodedenis.py:9142 +msgid "Abandon" +msgstr "" + +#: aperodedenis.py:614 +msgid "molette de la souris = zoom," +msgstr "" + +#: aperodedenis.py:615 +msgid "utilisable avant ET pendant le tracé" +msgstr "" + +#: aperodedenis.py:616 +msgid "glisser-déposer actif avant le tracé=" +msgstr "" + +#: aperodedenis.py:617 +msgid "Tracer :" +msgstr "" + +#: aperodedenis.py:618 +msgid "" +"Clic gauche : ajouter un point;\n" +" double clic gauche : fermer le polygone," +msgstr "" + +#: aperodedenis.py:619 +msgid "Touche Del pour supprimer un point ou le polygone," +msgstr "" + +#: aperodedenis.py:696 +msgid "Il faut au moins 2 points dans le polygone." +msgstr "" + +#: aperodedenis.py:726 aperodedenis.py:1014 +msgid "Zoom maximum atteint" +msgstr "" + +#: aperodedenis.py:812 +msgid "Erreur suppression d'info bulle : " +msgstr "" + +#: aperodedenis.py:874 +msgid "Calibration GPS " +msgstr "" + +#: aperodedenis.py:875 +msgid "Position des points sur la photo : " +msgstr "" + +#: aperodedenis.py:924 +msgid "Supprimer un ou plusieurs points" +msgstr "" + +#: aperodedenis.py:932 +msgid "Changer la couleur des libellés" +msgstr "" + +#: aperodedenis.py:939 +msgid "Utiliser la molette pour zoomer/dezoomer pendant la saisie." +msgstr "" + +#: aperodedenis.py:956 +msgid "Placer le point " +msgstr "" + +#: aperodedenis.py:959 +msgid "Point " +msgstr "" + +#: aperodedenis.py:1167 aperodedenis.py:1168 +msgid " : une interface graphique pour MicMac..." +msgstr "" + +#: aperodedenis.py:1172 +msgid "Fermeture inatendue de la fenêtre." +msgstr "" + +#: aperodedenis.py:1175 +msgid "Erreur initialisation de la fenêtre principale : " +msgstr "" + +#: aperodedenis.py:1195 aperodedenis.py:6228 +msgid "Nouveau chantier" +msgstr "" + +#: aperodedenis.py:1196 +msgid "Ouvrir un chantier" +msgstr "" + +#: aperodedenis.py:1198 +msgid "Enregistrer le chantier en cours" +msgstr "" + +#: aperodedenis.py:1199 +msgid "Renommer ou déplacer le chantier en cours" +msgstr "" + +#: aperodedenis.py:1201 +msgid "Exporter le chantier en cours" +msgstr "" + +#: aperodedenis.py:1202 +msgid "Importer un chantier" +msgstr "" + +#: aperodedenis.py:1204 +msgid "Du ménage !" +msgstr "" + +#: aperodedenis.py:1206 +msgid "Quitter" +msgstr "" + +#: aperodedenis.py:1211 +msgid "Afficher l'état du chantier" +msgstr "" + +#: aperodedenis.py:1213 +msgid "Visualiser toutes les photos sélectionnées" +msgstr "" + +#: aperodedenis.py:1214 +msgid "Visualiser les points GPS" +msgstr "" + +#: aperodedenis.py:1215 +msgid "Visualiser les maîtresses et les masques" +msgstr "" + +#: aperodedenis.py:1216 +msgid "Visualiser le masque sur mosaique Tarama" +msgstr "" + +#: aperodedenis.py:1217 +msgid "Visualiser le masque 3D" +msgstr "" + +#: aperodedenis.py:1218 +msgid "Visualiser la ligne horizontale/verticale" +msgstr "" + +#: aperodedenis.py:1219 +msgid "Visualiser la zone plane" +msgstr "" + +#: aperodedenis.py:1220 +msgid "Visualiser la distance" +msgstr "" + +#: aperodedenis.py:1221 +msgid "Visualiser les photos pour la calibration intrinsèque" +msgstr "" + +#: aperodedenis.py:1223 +msgid "Afficher la trace complète du chantier" +msgstr "" + +#: aperodedenis.py:1224 +msgid "Afficher la trace synthétique du chantier" +msgstr "" + +#: aperodedenis.py:1226 +msgid "Afficher la mosaïque Tarama" +msgstr "" + +#: aperodedenis.py:1227 +msgid "Afficher l'ortho mosaïque Tawny" +msgstr "" + +#: aperodedenis.py:1229 +msgid "Afficher l'image 3D non densifiée" +msgstr "" + +#: aperodedenis.py:1230 +msgid "Afficher l'image 3D densifiée" +msgstr "" + +#: aperodedenis.py:1232 +msgid "Lister-Visualiser les images 3D" +msgstr "" + +#: aperodedenis.py:1233 +msgid "Fusionner des images 3D" +msgstr "" + +#: aperodedenis.py:1240 aperodedenis.py:3477 +msgid "Choisir des photos" +msgstr "" + +#: aperodedenis.py:1241 +msgid "Options" +msgstr "" + +#: aperodedenis.py:1243 +msgid "Lancer MicMac" +msgstr "" + +#: aperodedenis.py:1248 +msgid "Options (GoPro par défaut)" +msgstr "" + +#: aperodedenis.py:1250 +msgid "Nouveau chantier : choisir une vidéo GoPro, ou autre" +msgstr "" + +#: aperodedenis.py:1251 +msgid "Sélection des meilleures images" +msgstr "" + +#: aperodedenis.py:1257 +msgid "Nom et focale de l'appareil photo" +msgstr "" + +#: aperodedenis.py:1258 +msgid "Toutes les focales des photos" +msgstr "" + +#: aperodedenis.py:1259 +msgid "Mettre à jour DicoCamera.xml" +msgstr "" + +#: aperodedenis.py:1261 +msgid "Qualité des photos du dernier traitement" +msgstr "" + +#: aperodedenis.py:1262 +msgid "Sélectionner les N meilleures photos" +msgstr "" + +#: aperodedenis.py:1264 +msgid "Qualité des photos 'line'" +msgstr "" + +#: aperodedenis.py:1265 +msgid "Qualité des photos 'All' " +msgstr "" + +#: aperodedenis.py:1267 +msgid "Modifier l'exif des photos" +msgstr "" + +#: aperodedenis.py:1269 aperodedenis.py:8773 aperodedenis.py:8791 +msgid "Modifier les options par défaut" +msgstr "" + +#: aperodedenis.py:1274 +msgid "Exécuter lignes de commande" +msgstr "" + +#: aperodedenis.py:1280 +msgid "Désactiver le 'tacky' message de lancement" +msgstr "" + +#: aperodedenis.py:1282 +msgid "Activer le 'tacky' message de lancement" +msgstr "" + +#: aperodedenis.py:1285 +msgid "Afficher les paramètres" +msgstr "" + +#: aperodedenis.py:1287 +msgid "Associer le répertoire bin de MicMac" +msgstr "" + +#: aperodedenis.py:1288 +msgid "Associer 'exiftool'" +msgstr "" + +#: aperodedenis.py:1289 +msgid "Associer 'convert' d'ImageMagick" +msgstr "" + +#: aperodedenis.py:1290 +msgid "Associer 'ffmpeg (décompacte les vidéos)" +msgstr "" + +#: aperodedenis.py:1291 +msgid "Associer 'Meshlab' ou 'CloudCompare'" +msgstr "" + +#: aperodedenis.py:1293 +msgid "Changer la langue" +msgstr "" + +#: aperodedenis.py:1295 +msgid "Désactive/Active le tacky message de lancement..." +msgstr "" + +#: aperodedenis.py:1300 +msgid "Affichage de la surface interpolée" +msgstr "" + +#: aperodedenis.py:1301 +msgid "Calcul des indices" +msgstr "" + +#: aperodedenis.py:1302 +msgid "Calcul de la PMP" +msgstr "" + +#: aperodedenis.py:1307 +msgid "Pour commencer..." +msgstr "" + +#: aperodedenis.py:1308 aperodedenis.py:1323 +msgid "Aide" +msgstr "" + +#: aperodedenis.py:1309 +msgid "Quelques conseils" +msgstr "" + +#: aperodedenis.py:1310 +msgid "Historique" +msgstr "" + +#: aperodedenis.py:1311 +msgid "A Propos" +msgstr "" + +#: aperodedenis.py:1315 +msgid "Fichier" +msgstr "" + +#: aperodedenis.py:1316 +msgid "Edition" +msgstr "" + +#: aperodedenis.py:1318 +msgid "Vidéo" +msgstr "" + +#: aperodedenis.py:1319 +msgid "Outils" +msgstr "" + +#: aperodedenis.py:1320 +msgid "Expert" +msgstr "" + +#: aperodedenis.py:1321 +msgid "Paramétrage" +msgstr "" + +#: aperodedenis.py:1356 +msgid "Pas de répertoire désigné pour MicMac\\bin" +msgstr "" + +#: aperodedenis.py:1357 +msgid "Pas de fichier désigné pour ouvrir les .PLY" +msgstr "" + +#: aperodedenis.py:1358 +msgid "Pas de chemin pour ExifTool" +msgstr "" + +#: aperodedenis.py:1359 +msgid "Pas de fichier pour mm3d" +msgstr "" + +#: aperodedenis.py:1360 +msgid "Pas de fichier pour ffmpeg" +msgstr "" + +#: aperodedenis.py:1361 +msgid "Pas de version MicMac" +msgstr "" + +#: aperodedenis.py:1363 +msgid "Pas de version Image Magick" +msgstr "" + +#: aperodedenis.py:1491 aperodedenis.py:1511 +msgid "Echelle image (-1 pour l'image entière) :" +msgstr "" + +#: aperodedenis.py:1499 +msgid "Echelle image réduite : " +msgstr "" + +#: aperodedenis.py:1503 +msgid "Seconde Echelle (-1 pour l'image entière) :" +msgstr "" + +#: aperodedenis.py:1513 +msgid "Delta (nombre d'images se recouvrant, avant et après) : " +msgstr "" + +#: aperodedenis.py:1541 +msgid "Choisir quelques photos pour la calibration intrinsèques" +msgstr "" + +#: aperodedenis.py:1544 +msgid " N'utiliser ces photos que pour la calibration" +msgstr "" + +#: aperodedenis.py:1544 +msgid "(exemple : focales différentes)" +msgstr "" + +#: aperodedenis.py:1545 +msgid "Toutes ces photos doivent avoir la même focale," +msgstr "" + +#: aperodedenis.py:1545 +msgid "éventuellement différente de la focale des autres photos." +msgstr "" + +#: aperodedenis.py:1547 +msgid "" +"lancer Tarama après TAPAS : mosaique pouvant définir un masque pour Malt/" +"ortho)" +msgstr "" + +#: aperodedenis.py:1550 +msgid "Arrêter le traitement après TAPAS" +msgstr "" + +#: aperodedenis.py:1571 aperodedenis.py:1606 +msgid "Choisir entre :" +msgstr "" + +#: aperodedenis.py:1574 +msgid "Ligne horizontale" +msgstr "" + +#: aperodedenis.py:1578 aperodedenis.py:1613 +msgid "ou" +msgstr "" + +#: aperodedenis.py:1581 +msgid "Ligne verticale" +msgstr "" + +#: aperodedenis.py:1594 aperodedenis.py:1628 +msgid "ET :" +msgstr "" + +#: aperodedenis.py:1609 +msgid "Zone plane horizontale" +msgstr "" + +#: aperodedenis.py:1616 +msgid "Zone plane verticale" +msgstr "" + +#: aperodedenis.py:1639 +msgid "Distance entre les 2 points :" +msgstr "" + +#: aperodedenis.py:1644 +msgid "Placer 2 points identiques sur 2 photos" +msgstr "" + +#: aperodedenis.py:1654 +msgid "Pour annuler la calibration mettre la distance = 0" +msgstr "" + +#: aperodedenis.py:1661 +msgid "UrbanMNE pour photos urbaines" +msgstr "" + +#: aperodedenis.py:1662 +msgid "GeomImage pour photos du sol ou d'objets" +msgstr "" + +#: aperodedenis.py:1663 +msgid "Ortho pour orthophotos de terrain naturel [f(x,y)=z)]" +msgstr "" + +#: aperodedenis.py:1664 +msgid "AperoDeDenis choisit pour vous les options de GeomImage" +msgstr "" + +#: aperodedenis.py:1684 aperodedenis.py:4348 +msgid "Choisir les maîtresses" +msgstr "" + +#: aperodedenis.py:1686 aperodedenis.py:1720 +msgid "Tracer les masques" +msgstr "" + +#: aperodedenis.py:1687 +msgid "Pour supprimer un masque : supprimer la maitresse" +msgstr "" + +#: aperodedenis.py:1687 aperodedenis.py:1721 +msgid "Attention : Le masque 3D de C3DC a la priorité sur Malt" +msgstr "" + +#: aperodedenis.py:1689 +msgid "Nombre de photos à retenir autour de l'image maitresse (-1 = toutes) :" +msgstr "" + +#: aperodedenis.py:1696 +msgid "Zoom final : 8, 4, 2 ou 1 (8=le plus rapide, 1=le plus précis)" +msgstr "" + +#: aperodedenis.py:1703 +msgid "Lancer tawny après MALT" +msgstr "" + +#: aperodedenis.py:1704 +msgid "Tawny génère une ortho mosaïque qui sera drapée sur le nuage densifié." +msgstr "" + +#: aperodedenis.py:1705 +msgid "Saisir si besoin les paramètres facultatifs, exemple :" +msgstr "" + +#: aperodedenis.py:1708 +msgid "Liste des paramètres facultatifs nommés :" +msgstr "" + +#: aperodedenis.py:1712 +msgid "Tracer un masque sur la mosaïque Tarama" +msgstr "" + +#: aperodedenis.py:1718 +msgid "La saisie des masques n'est active qu'aprés Tapas." +msgstr "" + +#: aperodedenis.py:1719 aperodedenis.py:2858 aperodedenis.py:4401 +#: aperodedenis.py:4402 +msgid "Pas de masque." +msgstr "" + +#: aperodedenis.py:1722 +msgid "" +"Pour supprimer un masque : supprimer la maitresse dans l'option GeomImage" +msgstr "" + +#: aperodedenis.py:1723 +msgid "Remarque : les masques sont communs à GeomImage et AperoDeDenis" +msgstr "" + +#: aperodedenis.py:1724 +msgid "Consulter la documentation." +msgstr "" + +#: aperodedenis.py:1752 +msgid "Statue - avec drapage" +msgstr "" + +#: aperodedenis.py:1753 +msgid "QuickMac - rapide, sans drapage" +msgstr "" + +#: aperodedenis.py:1759 +msgid "Tracer le masque 3D sur le nuage AperiCloud" +msgstr "" + +#: aperodedenis.py:1761 +msgid "Supprimer le masque 3D" +msgstr "" + +#: aperodedenis.py:1764 +msgid "Dans l'outil : " +msgstr "" + +#: aperodedenis.py:1765 +msgid "Définir le masque : F9 " +msgstr "" + +#: aperodedenis.py:1766 +msgid "Ajouter un point : clic gauche" +msgstr "" + +#: aperodedenis.py:1767 +msgid "Fermer le polygone : clic droit" +msgstr "" + +#: aperodedenis.py:1768 +msgid "Sélectionner : touche espace" +msgstr "" + +#: aperodedenis.py:1769 +msgid "Sauver le masque : Ctrl S." +msgstr "" + +#: aperodedenis.py:1770 +msgid "Quitter : Ctrl Q." +msgstr "" + +#: aperodedenis.py:1771 +msgid "Agrandir les points : Maj +" +msgstr "" + +#: aperodedenis.py:1772 +msgid "Saisie simultanée de plusieurs masques disjoints possible" +msgstr "" + +#: aperodedenis.py:1773 +msgid "C3DC a la priorité sur le masque 2D de Malt" +msgstr "" + +#: aperodedenis.py:1791 +msgid " Valider les options" +msgstr "" + +#: aperodedenis.py:1794 aperodedenis.py:1816 aperodedenis.py:1874 +#: aperodedenis.py:1921 aperodedenis.py:1995 aperodedenis.py:2022 +msgid " Annuler" +msgstr "" + +#: aperodedenis.py:1807 +msgid "Indiquer les dimensions du capteur, en mm." +msgstr "" + +#: aperodedenis.py:1808 +msgid "par exemple :" +msgstr "" + +#: aperodedenis.py:1809 +msgid "Le site :" +msgstr "" + +#: aperodedenis.py:1810 +msgid "fournit les dimensions de tous les appareils photos." +msgstr "" + +#: aperodedenis.py:1813 aperodedenis.py:1871 aperodedenis.py:2019 +msgid " Valider" +msgstr "" + +#: aperodedenis.py:1849 aperodedenis.py:1975 +msgid "Marque de l'appareil : " +msgstr "" + +#: aperodedenis.py:1853 +msgid "Nom de la camera : " +msgstr "" + +#: aperodedenis.py:1857 aperodedenis.py:1983 +msgid "Focale en mm:" +msgstr "" + +#: aperodedenis.py:1861 aperodedenis.py:1987 +msgid "Focale équivalente 35mm :" +msgstr "" + +#: aperodedenis.py:1865 +msgid "Nombre d'images à conserver par seconde :" +msgstr "" + +#: aperodedenis.py:1907 aperodedenis.py:1930 +msgid "linéaire" +msgstr "" + +#: aperodedenis.py:1908 +msgid "cubique" +msgstr "" + +#: aperodedenis.py:1911 +msgid " Choisir la méthode d'interpolation " +msgstr "" + +#: aperodedenis.py:1913 +msgid " Choisir le pas du maillage " +msgstr "" + +#: aperodedenis.py:1918 aperodedenis.py:1951 +msgid "Valider " +msgstr "" + +#: aperodedenis.py:1947 +msgid "Choisir profil à afficher " +msgstr "" + +#: aperodedenis.py:1954 +msgid "Annuler " +msgstr "" + +#: aperodedenis.py:1975 +msgid "Modification des Exif" +msgstr "" + +#: aperodedenis.py:1979 +msgid "Modèle de l'appareil: " +msgstr "" + +#: aperodedenis.py:1992 +msgid "Valider et mettre à jour" +msgstr "" + +#: aperodedenis.py:2014 +msgid "Indiquer le nombre de photos à retenir." +msgstr "" + +#: aperodedenis.py:2015 +msgid "" +"Un nouveau chantier sera créé avec les photos ayant, par paire, le plus de " +"points homologues" +msgstr "" + +#: aperodedenis.py:2016 +msgid "Ce choix est différent du nombre moyen de points homologues par photo." +msgstr "" + +#: aperodedenis.py:2037 +msgid "MicMac est une réalisation de l'IGN" +msgstr "" + +#: aperodedenis.py:2324 +msgid "Quelles options par défaut utiliser pour les nouveaux chantiers ?" +msgstr "" + +#: aperodedenis.py:2325 +msgid "Les options par défaut concernent :" +msgstr "" + +#: aperodedenis.py:2326 +msgid "Tapioca : All, MulScale, line ,les échelles et delta" +msgstr "" + +#: aperodedenis.py:2327 +msgid "Tapas : RadialExtended,RadialStandard, Radialbasic, arrêt aprés Tapas" +msgstr "" + +#: aperodedenis.py:2328 +msgid "Malt : mode, zoom final, nombre de photos autour de la maîtresse" +msgstr "" + +#: aperodedenis.py:2329 +msgid "Tawny et ses options en saisie libre" +msgstr "" + +#: aperodedenis.py:2330 +msgid "C3DC : mode (Statue ou QuickMac)" +msgstr "" + +#: aperodedenis.py:2369 +msgid "Pas de répertoire pour les photos" +msgstr "" + +#: aperodedenis.py:2470 aperodedenis.py:2492 +msgid "Enregistrer le chantier ?" +msgstr "" + +#: aperodedenis.py:2471 aperodedenis.py:2493 +msgid "Chantier non encore enregistré. Voulez-vous l'enregistrer ?" +msgstr "" + +#: aperodedenis.py:2472 aperodedenis.py:2480 aperodedenis.py:2494 +#: aperodedenis.py:2501 aperodedenis.py:8900 +msgid "Enregistrer" +msgstr "" + +#: aperodedenis.py:2473 aperodedenis.py:2481 aperodedenis.py:2495 +#: aperodedenis.py:2502 aperodedenis.py:8900 +msgid "Ne pas enregistrer." +msgstr "" + +#: aperodedenis.py:2475 aperodedenis.py:2483 aperodedenis.py:2497 +#: aperodedenis.py:2504 aperodedenis.py:8902 +msgid "Chantier précédent enregistré : %s" +msgstr "" + +#: aperodedenis.py:2478 aperodedenis.py:2499 aperodedenis.py:8898 +msgid "Enregistrer le chantier %s ?" +msgstr "" + +#: aperodedenis.py:2479 aperodedenis.py:2500 aperodedenis.py:8899 +msgid "" +"Chantier modifié depuis la dernière sauvegarde. Voulez-vous l'enregistrer ?" +msgstr "" + +#: aperodedenis.py:2505 +msgid "Choisir un chantier." +msgstr "" + +#: aperodedenis.py:2507 +msgid "Aucun chantier choisi." +msgstr "" + +#: aperodedenis.py:2515 +msgid "Chantier choisi %s corrompu. Abandon." +msgstr "" + +#: aperodedenis.py:2519 +msgid "Chantier enregistré" +msgstr "" + +#: aperodedenis.py:2524 +msgid "Indiquer les photos à traiter avant d'enregistrer le chantier." +msgstr "" + +#: aperodedenis.py:2534 +msgid "Commencer par choisir les photos" +msgstr "" + +#: aperodedenis.py:2534 +msgid "Il n'a pas encore de nom, il ne peut être renommé." +msgstr "" + +#: aperodedenis.py:2534 +msgid "Le chantier est en cours de définition." +msgstr "" + +#: aperodedenis.py:2536 +msgid "Nouveau nom ou nouveau chemin pour le chantier %s :" +msgstr "" + +#: aperodedenis.py:2537 +msgid "Tout chemin relatif au chemin actuel est valide" +msgstr "" + +#: aperodedenis.py:2538 +msgid "Un chemin absolu sur la même unité disque est valide" +msgstr "" + +#: aperodedenis.py:2539 +msgid "Aucun fichier de l'arborescence du chantier ne doit être ouvert." +msgstr "" + +#: aperodedenis.py:2550 +msgid "Le nom du nouveau chantier %s existe déjà. Abandon." +msgstr "" + +#: aperodedenis.py:2553 +msgid "Le nouveau répertoire " +msgstr "" + +#: aperodedenis.py:2553 +msgid "Utiliser l'Export-Import." +msgstr "" + +#: aperodedenis.py:2553 +msgid "implique un changement de disque." +msgstr "" + +#: aperodedenis.py:2556 +msgid "pour le chantier est déjà utilisé." +msgstr "" + +#: aperodedenis.py:2556 aperodedenis.py:2559 +msgid "Choisissez un autre nom." +msgstr "" + +#: aperodedenis.py:2556 aperodedenis.py:2559 +msgid "Le répertoire" +msgstr "" + +#: aperodedenis.py:2559 +msgid "désigne un sous-répertoire du chantier en cours." +msgstr "" + +#: aperodedenis.py:2571 +msgid "Le renommage du chantier ne peut se faire actuellement," +msgstr "" + +#: aperodedenis.py:2571 +msgid "soit le nom fourni est incorrect," +msgstr "" + +#: aperodedenis.py:2572 +msgid "soit un fichier du chantier est ouvert par une autre application." +msgstr "" + +#: aperodedenis.py:2573 +msgid "erreur : " +msgstr "" + +#: aperodedenis.py:2573 +msgid "soit l'explorateur explore l'arborescence." +msgstr "" + +#: aperodedenis.py:2589 +msgid "Chantier :" +msgstr "" + +#: aperodedenis.py:2589 +msgid "Répertoire : " +msgstr "" + +#: aperodedenis.py:2589 +msgid "renommé en :" +msgstr "" + +#: aperodedenis.py:2645 +msgid "Pas de chantier en cours" +msgstr "" + +#: aperodedenis.py:2647 +msgid "Patience : chantier en cours d'archivage..." +msgstr "" + +#: aperodedenis.py:2649 +msgid "Archive " +msgstr "" + +#: aperodedenis.py:2649 +msgid "Taille =" +msgstr "" + +#: aperodedenis.py:2649 +msgid "créée sous " +msgstr "" + +#: aperodedenis.py:2654 +msgid "Choisir le nom de l'archive à importer." +msgstr "" + +#: aperodedenis.py:2656 +msgid "Export" +msgstr "" + +#: aperodedenis.py:2657 +msgid "Chantier à importer" +msgstr "" + +#: aperodedenis.py:2659 +msgid "Importation abandonnée." +msgstr "" + +#: aperodedenis.py:2662 +msgid " n'est pas un fichier d'export valide" +msgstr "" + +#: aperodedenis.py:2663 +msgid "ou alors, sous ubuntu,il lui manque le droit d'exécution." +msgstr "" + +#: aperodedenis.py:2667 +msgid "Choisir le répertoire dans lequel recopier le chantier." +msgstr "" + +#: aperodedenis.py:2671 +msgid " n'est pas un répertoire valide." +msgstr "" + +#: aperodedenis.py:2674 +msgid "Patience !" +msgstr "" + +#: aperodedenis.py:2674 +msgid "Recopie en cours dans" +msgstr "" + +#: aperodedenis.py:2682 +msgid "Le répertoire destination" +msgstr "" + +#: aperodedenis.py:2682 +msgid "existe déjà. Abandon" +msgstr "" + +#: aperodedenis.py:2693 aperodedenis.py:2702 +msgid "Erreur copie lors d'un import : " +msgstr "" + +#: aperodedenis.py:2694 aperodedenis.py:2703 +msgid "L'importation a échouée. Erreur : " +msgstr "" + +#: aperodedenis.py:2718 +msgid " absent" +msgstr "" + +#: aperodedenis.py:2734 +msgid "Chantier importé :" +msgstr "" + +#: aperodedenis.py:2734 +msgid "Répertoire :" +msgstr "" + +#: aperodedenis.py:2734 +msgid "Vous pouvez le renommer si besoin." +msgstr "" + +#: aperodedenis.py:2737 +msgid "Version de MicMac avant l'import : %s" +msgstr "" + +#: aperodedenis.py:2738 +msgid "Version de MicMac : %s" +msgstr "" + +#: aperodedenis.py:2741 +msgid "erreur affichage version lors de l'import d'un chantier : " +msgstr "" + +#: aperodedenis.py:2743 +msgid "Anomalie lors de l'importation : " +msgstr "" + +#: aperodedenis.py:2751 +msgid "erreur copie fichier param chantier : %(param)s vers %(rep)s erreur=" +msgstr "" + +#: aperodedenis.py:2754 +msgid "Erreur lors de la copie du fichier paramètre chantier" +msgstr "" + +#: aperodedenis.py:2754 +msgid "erreur :" +msgstr "" + +#: aperodedenis.py:2754 +msgid "vers" +msgstr "" + +#: aperodedenis.py:2776 +msgid "Répertoire des photos :" +msgstr "" + +#: aperodedenis.py:2778 +msgid "Répertoire de la vidéo :" +msgstr "" + +#: aperodedenis.py:2780 +msgid "Aucune photo sélectionnée." +msgstr "" + +#: aperodedenis.py:2783 +msgid " photos sélectionnées" +msgstr "" + +#: aperodedenis.py:2783 +msgid "(sans calibration si tapas executé) : " +msgstr "" + +#: aperodedenis.py:2785 +msgid " photos sélectionnées : " +msgstr "" + +#: aperodedenis.py:2788 +msgid "ATTENTION : plusieurs extensions différentes dans les photos choisies !" +msgstr "" + +#: aperodedenis.py:2788 +msgid "Le traitement ne se fera que sur un type de fichier." +msgstr "" + +#: aperodedenis.py:2793 aperodedenis.py:2807 aperodedenis.py:2847 +msgid "Mode : " +msgstr "" + +#: aperodedenis.py:2795 aperodedenis.py:2797 +msgid "Echelle 1 : " +msgstr "" + +#: aperodedenis.py:2798 +msgid "Echelle 2 : " +msgstr "" + +#: aperodedenis.py:2800 +msgid "Echelle : " +msgstr "" + +#: aperodedenis.py:2801 +msgid "Delta : " +msgstr "" + +#: aperodedenis.py:2809 +msgid "Nombre de photos pour calibration intrinsèque : " +msgstr "" + +#: aperodedenis.py:2811 +msgid "Ces photos servent uniquement à la calibration." +msgstr "" + +#: aperodedenis.py:2813 +msgid "Tarama demandé aprés Tapas" +msgstr "" + +#: aperodedenis.py:2815 +msgid "Arrêt demandé après Tapas" +msgstr "" + +#: aperodedenis.py:2820 +msgid "Calibration présente" +msgstr "" + +#: aperodedenis.py:2823 +msgid "Calibration annulée : distance=0" +msgstr "" + +#: aperodedenis.py:2825 +msgid "Calibration incomplète :" +msgstr "" + +#: aperodedenis.py:2837 +msgid "C3DC : Masque 3D" +msgstr "" + +#: aperodedenis.py:2841 +msgid "La version installée de Micmac n'autorise pas les masques en 3D" +msgstr "" + +#: aperodedenis.py:2850 +msgid "Pas d'image maîtresse" +msgstr "" + +#: aperodedenis.py:2852 aperodedenis.py:2872 +msgid "Image maîtresse : " +msgstr "" + +#: aperodedenis.py:2854 aperodedenis.py:2874 aperodedenis.py:4395 +#: aperodedenis.py:4398 +msgid " images maîtresses" +msgstr "" + +#: aperodedenis.py:2856 +msgid "1 masque" +msgstr "" + +#: aperodedenis.py:2860 aperodedenis.py:4409 aperodedenis.py:4410 +msgid " masques" +msgstr "" + +#: aperodedenis.py:2862 +msgid "%s photos utiles autour de la maîtresse" +msgstr "" + +#: aperodedenis.py:2863 +msgid "les meilleures photos en correspondances seront choisies" +msgstr "" + +#: aperodedenis.py:2867 +msgid "Tawny lancé aprés Malt" +msgstr "" + +#: aperodedenis.py:2876 +msgid "arrêt au zoom : " +msgstr "" + +#: aperodedenis.py:2881 +msgid "Chantier en cours de définition." +msgstr "" + +#: aperodedenis.py:2885 +msgid "Chantier : " +msgstr "" + +#: aperodedenis.py:2892 +msgid "Chemin du chantier :" +msgstr "" + +#: aperodedenis.py:2894 +msgid "Chantier en attente d'enregistrement." +msgstr "" + +#: aperodedenis.py:2896 +msgid "Chantier enregistré." +msgstr "" + +#: aperodedenis.py:2898 +msgid "Options du chantier modifiables." +msgstr "" + +#: aperodedenis.py:2900 +msgid "Chantier interrompu suite à erreur." +msgstr "" + +#: aperodedenis.py:2900 +msgid "Relancer micmac." +msgstr "" + +#: aperodedenis.py:2902 +msgid "Options de Malt/C3DC modifiables." +msgstr "" + +#: aperodedenis.py:2904 +msgid "Chantier terminé." +msgstr "" + +#: aperodedenis.py:2906 +msgid "Chantier exécuté puis débloqué." +msgstr "" + +#: aperodedenis.py:2912 +msgid "Nuage de point non densifié généré après Tapas." +msgstr "" + +#: aperodedenis.py:2916 +msgid "Nuage de point densifié généré après %s" +msgstr "" + +#: aperodedenis.py:2919 +msgid "Aucun nuage de point généré." +msgstr "" + +#: aperodedenis.py:2926 +msgid "Les caractéristiques du chantier précédent" +msgstr "" + +#: aperodedenis.py:2926 +msgid "n'ont pas pu être lues correctement." +msgstr "" + +#: aperodedenis.py:2927 +msgid "" +"Le fichier des paramètres est probablement incorrect ou vous avez changé la " +"version de l'interface." +msgstr "" + +#: aperodedenis.py:2928 +msgid "Certaines fonctions seront peut_être défaillantes." +msgstr "" + +#: aperodedenis.py:2929 +msgid "Désolé pour l'incident." +msgstr "" + +#: aperodedenis.py:2930 +msgid "Erreur : " +msgstr "" + +#: aperodedenis.py:2958 aperodedenis.py:2959 aperodedenis.py:2962 +msgid "Toutes les photos" +msgstr "" + +#: aperodedenis.py:2961 +msgid "Toutes les photos utiles" +msgstr "" + +#: aperodedenis.py:2962 +msgid "sans les %s photos pour calibration intrinseque" +msgstr "" + +#: aperodedenis.py:2968 aperodedenis.py:2979 aperodedenis.py:2990 +#: aperodedenis.py:3002 aperodedenis.py:3017 aperodedenis.py:3040 +#: aperodedenis.py:3064 aperodedenis.py:3081 aperodedenis.py:3092 +#: aperodedenis.py:3110 aperodedenis.py:3129 aperodedenis.py:8399 +#: aperodedenis.py:8416 +msgid "Fermer" +msgstr "" + +#: aperodedenis.py:2973 +msgid "Aucun point GPS saisi." +msgstr "" + +#: aperodedenis.py:2976 +msgid "Affichage des photos avec points GPS" +msgstr "" + +#: aperodedenis.py:2978 +msgid "seules les photos avec points sont montrées." +msgstr "" + +#: aperodedenis.py:2987 +msgid "Liste des images maîtresses et des masques " +msgstr "" + +#: aperodedenis.py:2987 +msgid "communs à GeomImage et AperoDedenis" +msgstr "" + +#: aperodedenis.py:2989 +msgid "Images maîtresses et masques" +msgstr "" + +#: aperodedenis.py:2993 +msgid "Pas de maîtresses définies pour ce chantier" +msgstr "" + +#: aperodedenis.py:2999 +msgid "Mosaique Tarama et masque " +msgstr "" + +#: aperodedenis.py:2999 +msgid "Option Ortho de Malt" +msgstr "" + +#: aperodedenis.py:3001 +msgid "Image maîtresse et masque" +msgstr "" + +#: aperodedenis.py:3008 +msgid "Pas de masque 3D pour ce chantier." +msgstr "" + +#: aperodedenis.py:3015 +msgid "Visaliser le masque 3D" +msgstr "" + +#: aperodedenis.py:3019 +msgid "Affichage du masque 3D :" +msgstr "" + +#: aperodedenis.py:3020 +msgid "Les points blancs du nuage sont dans le masque" +msgstr "" + +#: aperodedenis.py:3021 +msgid "Ce masque C3DC a la priorité sur le masque 2D de Malt" +msgstr "" + +#: aperodedenis.py:3022 +msgid "ATTENTION : pour continuer FERMER la fenêtre 3D" +msgstr "" + +#: aperodedenis.py:3023 +msgid "puis cliquer si besoin sur le bouton FERMER ci-dessus." +msgstr "" + +#: aperodedenis.py:3033 +msgid "horizontale" +msgstr "" + +#: aperodedenis.py:3035 +msgid "verticale" +msgstr "" + +#: aperodedenis.py:3037 +msgid "Visualiser l'image maîtresse et le plan horizontal ou vertical" +msgstr "" + +#: aperodedenis.py:3039 +msgid "Zone plane " +msgstr "" + +#: aperodedenis.py:3045 +msgid "Pas de plan horizontal ou vertical défini pour ce chantier" +msgstr "" + +#: aperodedenis.py:3055 +msgid "HORIZONTALE" +msgstr "" + +#: aperodedenis.py:3058 +msgid "VERTICALE" +msgstr "" + +#: aperodedenis.py:3061 +msgid "Affichage des photos avec ligne horizontale ou verticale" +msgstr "" + +#: aperodedenis.py:3063 +msgid "ligne " +msgstr "" + +#: aperodedenis.py:3067 +msgid "Pas de ligne horizontale ou verticale définie pour ce chantier" +msgstr "" + +#: aperodedenis.py:3073 +msgid "Pas de distance correcte définie pour ce chantier." +msgstr "" + +#: aperodedenis.py:3078 +msgid "Visualiser les photos avec distance" +msgstr "" + +#: aperodedenis.py:3080 +msgid "Valeur de la distance : " +msgstr "" + +#: aperodedenis.py:3086 +msgid "Pas de photos pour la calibration intrinsèque par Tapas." +msgstr "" + +#: aperodedenis.py:3089 +msgid "Les photos pour calibration intrinsèque (Tapas)" +msgstr "" + +#: aperodedenis.py:3091 +msgid "Calibration intrinsèque" +msgstr "" + +#: aperodedenis.py:3097 +msgid "Pas de mosaique. Choisir l'option Tarama de tapas." +msgstr "" + +#: aperodedenis.py:3103 +msgid "Echec de la conversion mosaique en JPG." +msgstr "" + +#: aperodedenis.py:3107 +msgid "Mosaique créée par Tarama" +msgstr "" + +#: aperodedenis.py:3115 +msgid "Pas d' ortho mosaique par Tawny. Choisir l'option Tawny de Malt." +msgstr "" + +#: aperodedenis.py:3122 +msgid "Echec de la conversion de la mosaïque TIF en JPG." +msgstr "" + +#: aperodedenis.py:3126 +msgid "Ortho mosaique créée par Tawny" +msgstr "" + +#: aperodedenis.py:3153 +msgid "Pas de trace de la trace !" +msgstr "" + +#: aperodedenis.py:3164 +msgid "Pas de nuage de points aprés Tapas." +msgstr "" + +#: aperodedenis.py:3166 +msgid "Programme pour ouvrir les .PLY non trouvéé." +msgstr "" + +#: aperodedenis.py:3171 aperodedenis.py:5382 +msgid "Pas de nuage de points aprés Malt ou C3DC." +msgstr "" + +#: aperodedenis.py:3173 aperodedenis.py:5384 +msgid "Programme pour ouvrir les .PLY non trouvé." +msgstr "" + +#: aperodedenis.py:3179 +msgid "Répertoire bin de MicMac : " +msgstr "" + +#: aperodedenis.py:3181 +msgid "Version MicMac :" +msgstr "" + +#: aperodedenis.py:3183 +msgid "Outil exiftool :" +msgstr "" + +#: aperodedenis.py:3185 +msgid "Outil convert d'ImageMagick :" +msgstr "" + +#: aperodedenis.py:3187 +msgid "Outil pour afficher les .ply :" +msgstr "" + +#: aperodedenis.py:3189 +msgid "Outil pour décompacter les vidéos (ffmpeg):" +msgstr "" + +#: aperodedenis.py:3191 +msgid "Répertoire d'AperoDeDenis :" +msgstr "" + +#: aperodedenis.py:3193 +msgid "Répertoire des paramètres :" +msgstr "" + +#: aperodedenis.py:3203 +msgid "Répertoire bin sous MICMAC : " +msgstr "" + +#: aperodedenis.py:3212 +msgid "Désigner le répertoire bin sous Micmac " +msgstr "" + +#: aperodedenis.py:3215 aperodedenis.py:3222 +msgid "Répertoire bin de Micmac :" +msgstr "" + +#: aperodedenis.py:3215 aperodedenis.py:3222 aperodedenis.py:3335 +#: aperodedenis.py:3356 aperodedenis.py:3376 aperodedenis.py:3397 +msgid "Abandon, pas de changement." +msgstr "" + +#: aperodedenis.py:3220 +msgid "" +"Le chemin du répertoire bin de micmac ne doit pas comporter le caractère " +"'espace'." +msgstr "" + +#: aperodedenis.py:3221 +msgid "Renommer le répertoire de MicMac." +msgstr "" + +#: aperodedenis.py:3236 +msgid "Le répertoire %s ne contient pas le fichier mm3d.exe. Abandon" +msgstr "" + +#: aperodedenis.py:3283 +msgid "Le répertoire %s ne contient pas le fichier mm3d. Abandon" +msgstr "" + +#: aperodedenis.py:3296 +msgid "Nouveau répertoire de Micmac :" +msgstr "" + +#: aperodedenis.py:3301 +msgid "Le programme mm3d est présent mais ne peut s'exécuter." +msgstr "" + +#: aperodedenis.py:3301 +msgid "Vérifier si la version est compatible avec le système. :" +msgstr "" + +#: aperodedenis.py:3303 +msgid "Abandon." +msgstr "" + +#: aperodedenis.py:3303 +msgid "Le programme mm3d est absent du répertoire choisi :" +msgstr "" + +#: aperodedenis.py:3303 +msgid "Répertoire bin sous MicMac incorrect." +msgstr "" + +#: aperodedenis.py:3308 +msgid "Chemin de exiftool :" +msgstr "" + +#: aperodedenis.py:3310 +msgid "Chemin de convert d'image Magick :" +msgstr "" + +#: aperodedenis.py:3312 +msgid "Chemin de ffmpeg :" +msgstr "" + +#: aperodedenis.py:3317 +msgid "Pas de version identifiée de MicMac" +msgstr "" + +#: aperodedenis.py:3318 +msgid "Nouvelle version de MicMac : " +msgstr "" + +#: aperodedenis.py:3325 +msgid "Pas de chemin pour le programme exiftool" +msgstr "" + +#: aperodedenis.py:3327 aperodedenis.py:3340 +msgid "Programme exiftool :" +msgstr "" + +#: aperodedenis.py:3333 +msgid "Recherche exiftool" +msgstr "" + +#: aperodedenis.py:3335 +msgid "Fichier exiftool inchangé :" +msgstr "" + +#: aperodedenis.py:3346 +msgid "Pas de chemin pour le programme convert d'ImageMagick" +msgstr "" + +#: aperodedenis.py:3348 aperodedenis.py:3361 +msgid "Programme convert :" +msgstr "" + +#: aperodedenis.py:3354 +msgid "Recherche convert" +msgstr "" + +#: aperodedenis.py:3356 +msgid "Fichier convert inchangé :" +msgstr "" + +#: aperodedenis.py:3367 +msgid "Pas de chemin pour le programme ouvrant les .PLY" +msgstr "" + +#: aperodedenis.py:3369 aperodedenis.py:3381 +msgid "Programme ouvrant les .PLY :" +msgstr "" + +#: aperodedenis.py:3373 +msgid "meshlab ou CloudCompare" +msgstr "" + +#: aperodedenis.py:3374 +msgid "Recherche fichier Meshlab sous VCG, ou CloudCompare" +msgstr "" + +#: aperodedenis.py:3376 +msgid "Fichier Meshlab ou cloud compare :" +msgstr "" + +#: aperodedenis.py:3387 +msgid "Pas de chemin pour le programme Ffmpeg" +msgstr "" + +#: aperodedenis.py:3389 aperodedenis.py:3402 +msgid "Programme ffmpeg :" +msgstr "" + +#: aperodedenis.py:3395 +msgid "Recherche ffmpeg" +msgstr "" + +#: aperodedenis.py:3397 +msgid "Fichier ffmpeg inchangé :" +msgstr "" + +#: aperodedenis.py:3408 +msgid "Tacky message au lancement activé" +msgstr "" + +#: aperodedenis.py:3410 +msgid "Tacky message au lancement désactivé" +msgstr "" + +#: aperodedenis.py:3414 +msgid "Sélectionnez la langue à utiliser. L'application sera redémarrée." +msgstr "" + +#: aperodedenis.py:3422 +msgid "Appliquer" +msgstr "" + +#: aperodedenis.py:3425 aperodedenis.py:3431 +msgid "Français" +msgstr "" + +#: aperodedenis.py:3426 +msgid "Anglais" +msgstr "" + +#: aperodedenis.py:3451 +msgid "" +"Avant de choisir les photos associer le répertoire bin de micmac (Menu " +"Paramétrage\\associer le répertoire bin de MicMac)." +msgstr "" + +#: aperodedenis.py:3455 +msgid "" +"Avant de choisir les photos associer le chemin du programme exiftool (Menu " +"trage\\Associer exiftool)." +msgstr "" + +#: aperodedenis.py:3463 +msgid "Nouvelles photos pour le meme chantier" +msgstr "" + +#: aperodedenis.py:3464 +msgid "Choisir de nouvelles photos réinitialisera le chantier." +msgstr "" + +#: aperodedenis.py:3465 +msgid "Les traces et l'arborescence des calculs seront effacées." +msgstr "" + +#: aperodedenis.py:3466 +msgid "Les options compatibles avec les nouvelles photos seront conservées." +msgstr "" + +#: aperodedenis.py:3468 +msgid "Réinitialiser le chantier" +msgstr "" + +#: aperodedenis.py:3469 +msgid "Abandon, le chantier n'est pas modifié." +msgstr "" + +#: aperodedenis.py:3479 +msgid "Photos" +msgstr "" + +#: aperodedenis.py:3483 +msgid "Abandon, aucune sélection de fichier image," +msgstr "" + +#: aperodedenis.py:3483 aperodedenis.py:3547 aperodedenis.py:6244 +msgid "le répertoire et les photos restent inchangés." +msgstr "" + +#: aperodedenis.py:3487 aperodedenis.py:3510 +msgid "Aucune extension acceptable pour des images. Abandon." +msgstr "" + +#: aperodedenis.py:3491 +msgid "Impossible dans cette version. Abandon." +msgstr "" + +#: aperodedenis.py:3491 +msgid "Plusieurs extensions différentes :" +msgstr "" + +#: aperodedenis.py:3496 +msgid "Info : format des photos" +msgstr "" + +#: aperodedenis.py:3496 +msgid "La version actuelle ne traite que les photos au format JPG," +msgstr "" + +#: aperodedenis.py:3496 +msgid "or le format des photos est : " +msgstr "" + +#: aperodedenis.py:3497 +msgid "les photos vont être converties au format JPG." +msgstr "" + +#: aperodedenis.py:3498 +msgid "Convertir en JPG" +msgstr "" + +#: aperodedenis.py:3499 aperodedenis.py:3527 +msgid "Abandonner" +msgstr "" + +#: aperodedenis.py:3502 +msgid "(Menu Paramétrage)" +msgstr "" + +#: aperodedenis.py:3502 +msgid "Désigner l'outil de conversation 'convert' d'ImageMagick" +msgstr "" + +#: aperodedenis.py:3524 +msgid "ATTENTION !" +msgstr "" + +#: aperodedenis.py:3524 +msgid "" +"ATTENTION : des points GPS ont été précedemment placés sur des photos non " +"choisies pour ce chantier." +msgstr "" + +#: aperodedenis.py:3525 +msgid "" +"Les emplacements de ces points vont être supprimés si vous validez cette " +"sélection de photos." +msgstr "" + +#: aperodedenis.py:3526 +msgid "Valider la sélection de photos" +msgstr "" + +#: aperodedenis.py:3535 +msgid "Copie des photos en cours... Patience" +msgstr "" + +#: aperodedenis.py:3544 aperodedenis.py:6241 +msgid "Impossible de créer le répertoire de travail." +msgstr "" + +#: aperodedenis.py:3544 aperodedenis.py:6241 +msgid "Vérifier les droits en écriture sous le répertoire des photos" +msgstr "" + +#: aperodedenis.py:3547 aperodedenis.py:6244 +msgid "Aucun JPG, PNG, BMP, TIF, ou GIF sélectionné," +msgstr "" + +#: aperodedenis.py:3560 +msgid "L'outil exiftool n'est pas localisé : controle des photos impossible." +msgstr "" + +#: aperodedenis.py:3560 aperodedenis.py:8748 +msgid "Désigner le fichier exiftool (menu paramétrage)." +msgstr "" + +#: aperodedenis.py:3562 +msgid "Les focales sont absentes des exif." +msgstr "" + +#: aperodedenis.py:3562 +msgid "Mettez à jour les exifs avant de lancer MicMac." +msgstr "" + +#: aperodedenis.py:3563 +msgid "Utiliser le menu Outils/Modifier l'exif des photos." +msgstr "" + +#: aperodedenis.py:3565 +msgid "Attention : Les focales des photos ou ne sont pas toutes identiques." +msgstr "" + +#: aperodedenis.py:3568 +msgid "Attention : les dimensions des photos ne sont pas toutes identiques." +msgstr "" + +#: aperodedenis.py:3569 +msgid "Le traitement par MicMac ne sera peut-être pas possible." +msgstr "" + +#: aperodedenis.py:3581 +msgid "De nouvelles photos ont été sélectionnés sur un chantier pré-existant." +msgstr "" + +#: aperodedenis.py:3582 +msgid "" +"Les anciennes options compatibles avec les nouvelles photos ont été " +"conservées." +msgstr "" + +#: aperodedenis.py:3632 +msgid "Causes possibles : manque d'espace disque ou droits insuffisants." +msgstr "" + +#: aperodedenis.py:3632 +msgid "dans le répertoire " +msgstr "" + +#: aperodedenis.py:3632 +msgid "erreur lors de la copie du fichier" +msgstr "" + +#: aperodedenis.py:3632 +msgid "libellé de l'erreur :" +msgstr "" + +#: aperodedenis.py:3680 +msgid "erreur controle des photos : " +msgstr "" + +#: aperodedenis.py:3710 +msgid "Impossible de créer le répertoire de travail : erreur = " +msgstr "" + +#: aperodedenis.py:3724 +msgid "Le chantier est interrompu suite à incident. " +msgstr "" + +#: aperodedenis.py:3725 +msgid "" +"Si besoin créer un nouveau chantier ou débloquer le chantier en lancant " +"micmac." +msgstr "" + +#: aperodedenis.py:3735 +msgid "Le chantier %(x)s est terminé." +msgstr "" + +#: aperodedenis.py:3736 +msgid "Le chantier est terminé après " +msgstr "" + +#: aperodedenis.py:3737 +msgid "Vous pouvez :" +msgstr "" + +#: aperodedenis.py:3738 +msgid " - Nettoyer le chantier pour modifier les options de Tapioca et Tapas" +msgstr "" + +#: aperodedenis.py:3739 +msgid "" +" - Conserver les traitements de Tapioca/Tapas pour modifier les options de " +"Malt ou C3DC" +msgstr "" + +#: aperodedenis.py:3740 +msgid " - Ne rien faire." +msgstr "" + +#: aperodedenis.py:3741 +msgid "Modifier les options de Tapioca et Tapas" +msgstr "" + +#: aperodedenis.py:3742 +msgid "Modifier les options de Malt ou C3DC" +msgstr "" + +#: aperodedenis.py:3743 +msgid "Ne rien faire" +msgstr "" + +#: aperodedenis.py:3772 aperodedenis.py:4301 +msgid "Nombre de photos choisies : " +msgstr "" + +#: aperodedenis.py:3798 +msgid "Suppression du masque 3D : la version de MicMac ne comporte pas C3DC" +msgstr "" + +#: aperodedenis.py:3807 +msgid "lancer Micmac pour en constituer un." +msgstr "" + +#: aperodedenis.py:3807 +msgid "pas de fichier AperiCloud.ply pour construire le masque :" +msgstr "" + +#: aperodedenis.py:3812 aperodedenis.py:4584 +msgid "Masque 3D créé" +msgstr "" + +#: aperodedenis.py:3814 +msgid "Pas de masque 3D" +msgstr "" + +#: aperodedenis.py:3849 aperodedenis.py:5488 +msgid "Option incorrecte :" +msgstr "" + +#: aperodedenis.py:3863 +msgid "Points GPS non conformes. Nom est absent ou en double. Vérifiez." +msgstr "" + +#: aperodedenis.py:3871 aperodedenis.py:6468 +msgid "Nom" +msgstr "" + +#: aperodedenis.py:3890 +msgid "NomPhoto" +msgstr "" + +#: aperodedenis.py:3892 aperodedenis.py:3900 +msgid "NomPoint" +msgstr "" + +#: aperodedenis.py:3927 +msgid "Pas de points GPS." +msgstr "" + +#: aperodedenis.py:3933 +msgid "%s points GPS placés" +msgstr "" + +#: aperodedenis.py:3934 +msgid "pour %s points GPS définis" +msgstr "" + +#: aperodedenis.py:3936 +msgid "" +"Attention : il faut au moins 3 points pour qu'ils soient pris en compte." +msgstr "" + +#: aperodedenis.py:3955 +msgid "" +"Il n'y a pas 3 points placés sur 2 photos : les points GPS seront ignorés." +msgstr "" + +#: aperodedenis.py:3958 +msgid "" +"Anomalie : les points suivants ne sont placés que sur une seule photo : " +msgstr "" + +#: aperodedenis.py:3961 +msgid "Anomalie : le point suivant n'est placé que sur une seule photo : " +msgstr "" + +#: aperodedenis.py:3966 +msgid "Saisie incomplète : les points GPS ne seront pas pris en compte" +msgstr "" + +#: aperodedenis.py:3981 +msgid "La ligne horizontale ou verticale ne comporte pas 2 points" +msgstr "" + +#: aperodedenis.py:3984 +msgid "Pas de maitre plan horizontal ou vertical" +msgstr "" + +#: aperodedenis.py:3988 +msgid "Pas de plan horizontal ou vertical" +msgstr "" + +#: aperodedenis.py:3993 +msgid "%(x)s Distance %(y)s invalide." +msgstr "" + +#: aperodedenis.py:3995 +msgid "Calibration annulée." +msgstr "" + +#: aperodedenis.py:3997 +msgid "%s Pas de distance." +msgstr "" + +#: aperodedenis.py:4003 +msgid "La distance n'est pas mesurée par 2 points repérés sur 2 photos." +msgstr "" + +#: aperodedenis.py:4006 aperodedenis.py:4009 +msgid "La photo avec distance %s est absente." +msgstr "" + +#: aperodedenis.py:4011 +msgid "Pas de distance pour la calibration." +msgstr "" + +#: aperodedenis.py:4028 +msgid "Fichiers" +msgstr "" + +#: aperodedenis.py:4119 +msgid "" +"L'échelle pour le mode All de Tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "" + +#: aperodedenis.py:4123 +msgid "Echelle pour le mode All de Tapioca trop petite :" +msgstr "" + +#: aperodedenis.py:4123 aperodedenis.py:4162 +msgid "Minimum = 50" +msgstr "" + +#: aperodedenis.py:4135 +msgid "" +"L'échelle 1 pour MulScale de Tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "" + +#: aperodedenis.py:4139 +msgid "Elle est mise à 300." +msgstr "" + +#: aperodedenis.py:4139 +msgid "L'échelle 1 de MulScale ne doit pas être -1." +msgstr "" + +#: aperodedenis.py:4146 +msgid "L'échelle 1 pour le mode MulScale de Tapioca est trop petite : " +msgstr "" + +#: aperodedenis.py:4146 +msgid "Minimum = 50, maximum conseillé : 300" +msgstr "" + +#: aperodedenis.py:4158 +msgid "" +"L'échelle 2 pour le mode MulScale de Tapioca est invalide, une valeur par " +"défaut, %s, est affectée." +msgstr "" + +#: aperodedenis.py:4162 +msgid "L'échelle 2 pour le mode MulScale de Tapioca est trop petite :" +msgstr "" + +#: aperodedenis.py:4170 +msgid "L'échelle 2 de MulScale pour tapioca" +msgstr "" + +#: aperodedenis.py:4170 +msgid "plus petite que l'échelle 1 :" +msgstr "" + +#: aperodedenis.py:4182 +msgid "" +"L'échelle pour le mode Line de tapioca est invalide, une valeur par défaut, " +"%s, est affectée." +msgstr "" + +#: aperodedenis.py:4186 +msgid "Echelle pour le mode Line de tapioca trop petite : " +msgstr "" + +#: aperodedenis.py:4198 +msgid "La valeur de delta pour le mode Line de Tapioca est invalide," +msgstr "" + +#: aperodedenis.py:4198 +msgid "une valeur par défaut, %s, est affectée." +msgstr "" + +#: aperodedenis.py:4202 +msgid "Delta trop petit :" +msgstr "" + +#: aperodedenis.py:4202 +msgid "Minimum = 1" +msgstr "" + +#: aperodedenis.py:4209 +msgid "Le zoom final pour MALT n'est pas 1,2,4 ou 8 : %s" +msgstr "" + +#: aperodedenis.py:4223 +msgid "" +"Le nombre de photos utiles autour de l'image maîtresse est trop petit : %s" +msgstr "" + +#: aperodedenis.py:4223 aperodedenis.py:4225 +msgid "Malt mode Geomimage :" +msgstr "" + +#: aperodedenis.py:4225 +msgid "Il est mis à 5." +msgstr "" + +#: aperodedenis.py:4225 +msgid "" +"Le nombre de photos utiles autour de l'image centrale n'est pas numérique : " +msgstr "" + +#: aperodedenis.py:4233 +msgid "La photo %s n'existe plus." +msgstr "" + +#: aperodedenis.py:4238 +msgid "Inutile et ralenti le traitement. Modifier." +msgstr "" + +#: aperodedenis.py:4242 +msgid ", est plus grande que la dimension maxi de la photo : " +msgstr "" + +#: aperodedenis.py:4242 +msgid "L'échelle pour le mode All de tapioca = " +msgstr "" + +#: aperodedenis.py:4246 +msgid "L'échelle 2 pour le mode MulScale de tapioca= " +msgstr "" + +#: aperodedenis.py:4246 aperodedenis.py:4250 +msgid "est plus grande que la dimension maxi de la photo :" +msgstr "" + +#: aperodedenis.py:4250 +msgid "L'échelle pour le mode Line de tapioca = " +msgstr "" + +#: aperodedenis.py:4285 aperodedenis.py:4426 aperodedenis.py:4459 +#: aperodedenis.py:4790 aperodedenis.py:4874 aperodedenis.py:4916 +#: aperodedenis.py:4957 aperodedenis.py:4988 aperodedenis.py:5019 +msgid "Choisir d'abord les photos du chantier." +msgstr "" + +#: aperodedenis.py:4289 +msgid "Pour calibrer l'appareil photo" +msgstr "" + +#: aperodedenis.py:4290 +msgid "Quelques photos, convergentes, d'angles écartés" +msgstr "" + +#: aperodedenis.py:4290 +msgid "en jaune la calibration actuelle" +msgstr "" + +#: aperodedenis.py:4291 +msgid "Supprimer" +msgstr "" + +#: aperodedenis.py:4294 +msgid "Pas de photos de calibration intrinseque." +msgstr "" + +#: aperodedenis.py:4298 +msgid "Choix inchangé." +msgstr "" + +#: aperodedenis.py:4334 +msgid "Image maitresse avec masque" +msgstr "" + +#: aperodedenis.py:4349 +msgid "Choisir une ou plusieurs image(s) maîtresse(s)" +msgstr "" + +#: aperodedenis.py:4349 +msgid "Une info bulle informe de la présence d'un masque" +msgstr "" + +#: aperodedenis.py:4349 +msgid "en jaune : les maitresses actuelles" +msgstr "" + +#: aperodedenis.py:4350 +msgid "Supprimer les images maîtresses" +msgstr "" + +#: aperodedenis.py:4361 +msgid "Abandon. Choix inchangé." +msgstr "" + +#: aperodedenis.py:4380 +msgid "Image maitresse obligatoire pour GeomImage." +msgstr "" + +#: aperodedenis.py:4382 +msgid "Exécuter Tapioca/Tapas pour saisir des masques avec cette option." +msgstr "" + +#: aperodedenis.py:4388 aperodedenis.py:4391 +msgid "image maîtresse = " +msgstr "" + +#: aperodedenis.py:4405 aperodedenis.py:4406 +msgid "un seul masque : " +msgstr "" + +#: aperodedenis.py:4413 +msgid "Pas de mosaique Tarama : pas de masque." +msgstr "" + +#: aperodedenis.py:4416 +msgid "Tracer un nouveau masque sur la mosaique Tarama" +msgstr "" + +#: aperodedenis.py:4419 +msgid "Tracer un masque sur la mosaique Tarama" +msgstr "" + +#: aperodedenis.py:4422 +msgid "erreur dans miseAJour701_703 : " +msgstr "" + +#: aperodedenis.py:4431 aperodedenis.py:4498 +msgid "Il faut au moins une image maîtresse pour définir un masque." +msgstr "" + +#: aperodedenis.py:4438 aperodedenis.py:4474 +msgid "Un masque existe déjà" +msgstr "" + +#: aperodedenis.py:4440 aperodedenis.py:4476 aperodedenis.py:4508 +msgid "Choisir l'image pour le masque" +msgstr "" + +#: aperodedenis.py:4441 aperodedenis.py:4477 +msgid "" +"Choisir une image maîtresse pour le masque\n" +"en jaune = un masque existe" +msgstr "" + +#: aperodedenis.py:4462 +msgid "Exécuter d'abord Tapioca/Tapas." +msgstr "" + +#: aperodedenis.py:4466 +msgid "Pas d'image maîtresse. Bizarre." +msgstr "" + +#: aperodedenis.py:4509 +msgid "Choisir une image maîtresse pour le masque" +msgstr "" + +#: aperodedenis.py:4527 +msgid "pas de masque" +msgstr "" + +#: aperodedenis.py:4529 +msgid "Il faut une image maîtresse pour définir un masque." +msgstr "" + +#: aperodedenis.py:4586 +msgid "Abandon : pas de masque créé." +msgstr "" + +#: aperodedenis.py:4593 +msgid "Masque 3D supprimé." +msgstr "" + +#: aperodedenis.py:4613 +msgid "3 points minimum, chaque point doit être placé sur au moins 2 photos" +msgstr "" + +#: aperodedenis.py:4614 +msgid "La calibration par points GPS se fait aprés Tapas et avant Malt." +msgstr "" + +#: aperodedenis.py:4615 +msgid "Elle est prioritaire sur la calibration par axe, plan et métrique." +msgstr "" + +#: aperodedenis.py:4627 +msgid "Incertitude" +msgstr "" + +#: aperodedenis.py:4632 +msgid "Ajouter un point" +msgstr "" + +#: aperodedenis.py:4633 +msgid "Supprimer des points" +msgstr "" + +#: aperodedenis.py:4634 +msgid "Placer les points" +msgstr "" + +#: aperodedenis.py:4635 +msgid "Appliquer au " +msgstr "" + +#: aperodedenis.py:4635 +msgid "nuage non densifié" +msgstr "" + +#: aperodedenis.py:4691 +msgid "(ou si impossible : supprimer un point)" +msgstr "" + +#: aperodedenis.py:4691 +msgid "Agrandissez la fenêtre avant d'ajouter un point GPS !" +msgstr "" + +#: aperodedenis.py:4695 +msgid "Soyez raisonnable : pas plus de 30 points GPS !" +msgstr "" + +#: aperodedenis.py:4708 +msgid "Aucun point à supprimer !" +msgstr "" + +#: aperodedenis.py:4716 +msgid "Points à supprimer" +msgstr "" + +#: aperodedenis.py:4718 aperodedenis.py:7381 +msgid "Multiselection possible." +msgstr "" + +#: aperodedenis.py:4720 aperodedenis.py:7382 aperodedenis.py:7391 +#: aperodedenis.py:7397 aperodedenis.py:8213 aperodedenis.py:9099 +msgid "Annuler" +msgstr "" + +#: aperodedenis.py:4802 +msgid "Choisir une photo pour placer les points GPS : " +msgstr "" + +#: aperodedenis.py:4830 +msgid "Attention : des points portent le même nom : corriger !" +msgstr "" + +#: aperodedenis.py:4832 +msgid "Attention : un point n'a pas de nom. " +msgstr "" + +#: aperodedenis.py:4834 +msgid "controle points : " +msgstr "" + +#: aperodedenis.py:4845 +msgid "Lancer d'abord tapioca/tapas" +msgstr "" + +#: aperodedenis.py:4845 +msgid "pour obtenir un nuage non densifié." +msgstr "" + +#: aperodedenis.py:4852 aperodedenis.py:4856 +msgid "Points GPS non conformes :" +msgstr "" + +#: aperodedenis.py:4859 +msgid "Patienter :" +msgstr "" + +#: aperodedenis.py:4859 +msgid "le nuage est en cours de calibration" +msgstr "" + +#: aperodedenis.py:4876 +msgid "Extrémité Ox" +msgstr "" + +#: aperodedenis.py:4876 +msgid "Origine Ox" +msgstr "" + +#: aperodedenis.py:4883 +msgid "Placer une ligne horizontale sur une seule photo : " +msgstr "" + +#: aperodedenis.py:4908 +msgid "il faut placer les 2 points." +msgstr "" + +#: aperodedenis.py:4924 +msgid "Placer une ligne verticale sur une seule photo : : " +msgstr "" + +#: aperodedenis.py:4935 +msgid "Extrémité Oy" +msgstr "" + +#: aperodedenis.py:4935 +msgid "Origine Oy" +msgstr "" + +#: aperodedenis.py:4949 +msgid "il faut placer exactement 2 points." +msgstr "" + +#: aperodedenis.py:4961 aperodedenis.py:4992 +msgid "Plan vertical" +msgstr "" + +#: aperodedenis.py:4963 aperodedenis.py:4994 +msgid "Plan horizontal" +msgstr "" + +#: aperodedenis.py:4966 +msgid "Une photo pour placer le plan vertical : " +msgstr "" + +#: aperodedenis.py:4984 +msgid "Délimiter un plan vertical" +msgstr "" + +#: aperodedenis.py:4997 +msgid "Une photo pour placer le plan horizontal : " +msgstr "" + +#: aperodedenis.py:5015 +msgid "Délimiter un plan horizontal" +msgstr "" + +#: aperodedenis.py:5025 +msgid "Choisir deux fois une photo pour placer les 2 points : " +msgstr "" + +#: aperodedenis.py:5041 +msgid "" +"Il y a dèjà 2 images avec des points 'distance'. Supprimer les points sur " +"une des 2 images." +msgstr "" + +#: aperodedenis.py:5058 +msgid "Le chantier %(chant)s est terminé après %(densif)s" +msgstr "" + +#: aperodedenis.py:5059 +msgid "Vous pouvez modifier les options puis relancer MicMac." +msgstr "" + +#: aperodedenis.py:5078 +msgid "Options incorrectes : corriger" +msgstr "" + +#: aperodedenis.py:5084 +msgid "Avec 2 photos MicMac construira difficilement un nuage de point dense." +msgstr "" + +#: aperodedenis.py:5084 +msgid "Utiliser l'échelle -1 dans Tapioca pour obtenir un nuage optimal." +msgstr "" + +#: aperodedenis.py:5085 +msgid "Avertissement : 2 photos seulement" +msgstr "" + +#: aperodedenis.py:5087 aperodedenis.py:5113 aperodedenis.py:5124 +#: aperodedenis.py:5135 +msgid "Continuer" +msgstr "" + +#: aperodedenis.py:5105 +msgid "" +"Controle des photos en cours....\n" +"Patienter jusqu'à la fin du controle." +msgstr "" + +#: aperodedenis.py:5110 +msgid "Les dimensions des photos ne sont pas toutes identiques." +msgstr "" + +#: aperodedenis.py:5111 +msgid "Le traitement par MicMac est incertain." +msgstr "" + +#: aperodedenis.py:5113 aperodedenis.py:5135 +msgid "Avertissement" +msgstr "" + +#: aperodedenis.py:5120 +msgid "Absence de focales" +msgstr "" + +#: aperodedenis.py:5121 +msgid "Certaines photos n'ont pas de focales." +msgstr "" + +#: aperodedenis.py:5122 +msgid "Le traitement echouera probablement." +msgstr "" + +#: aperodedenis.py:5123 +msgid "Mettre à jour les exifs (menu Outils)" +msgstr "" + +#: aperodedenis.py:5132 +msgid "Les focales des photos ne sont pas toutes identiques." +msgstr "" + +#: aperodedenis.py:5133 +msgid "" +"Le traitement par MicMac est possible en utilisant une focale pour la " +"calibration intrinsèque de Tapas." +msgstr "" + +#: aperodedenis.py:5134 +msgid "Cependant vous pouvez essayer sans cela." +msgstr "" + +#: aperodedenis.py:5141 +msgid "Pas assez de photos pour le traitement : il en faut au moins 2." +msgstr "" + +#: aperodedenis.py:5148 +msgid "Le chantier %s a été interrompu en cours d'exécution." +msgstr "" + +#: aperodedenis.py:5149 +msgid "Le chantier est interrompu." +msgstr "" + +#: aperodedenis.py:5149 +msgid "Vous pouvez le débloquer," +msgstr "" + +#: aperodedenis.py:5150 +msgid "ce qui permettra de modifier les options et de le relancer." +msgstr "" + +#: aperodedenis.py:5151 +msgid "Débloquer le chantier" +msgstr "" + +#: aperodedenis.py:5157 aperodedenis.py:5184 +msgid "Chantier %s de nouveau modifiable, paramètrable et exécutable." +msgstr "" + +#: aperodedenis.py:5165 +msgid "Continuer le chantier %s après tapas ?" +msgstr "" + +#: aperodedenis.py:5166 +msgid "Le chantier est arrêté après tapas. Vous pouvez :" +msgstr "" + +#: aperodedenis.py:5167 +msgid " - lancer Malt, ou C3DC, pour obtenir un nuage dense" +msgstr "" + +#: aperodedenis.py:5168 +msgid " - débloquer le chantier pour modifier les paramètres de Tapioca/tapas" +msgstr "" + +#: aperodedenis.py:5169 +msgid " - ne rien faire" +msgstr "" + +#: aperodedenis.py:5170 +msgid "Lancer " +msgstr "" + +#: aperodedenis.py:5171 +msgid "Débloquer le chantier - garder les résultats" +msgstr "" + +#: aperodedenis.py:5174 +msgid "abandon de Malt" +msgstr "" + +#: aperodedenis.py:5178 +msgid "" +" Reprise du chantier %s arrêté aprés TAPAS - La trace depuis l'origine sera " +"disponible dans le menu édition." +msgstr "" + +#: aperodedenis.py:5247 aperodedenis.py:5256 +msgid "Pourquoi MicMac s'arrête : " +msgstr "" + +#: aperodedenis.py:5256 +msgid "Aucun point en correspondance sur 2 images n'a été trouvé par Tapioca." +msgstr "" + +#: aperodedenis.py:5257 +msgid "Parmi les raisons de cet échec il peut y avoir :" +msgstr "" + +#: aperodedenis.py:5258 +msgid "" +"soit l'exif des photos ne comporte pas la focale ou plusieurs focales sont " +"présentes" +msgstr "" + +#: aperodedenis.py:5259 +msgid "Soit l'appareil photo est inconnu de Micmac" +msgstr "" + +#: aperodedenis.py:5260 +msgid "soit la qualité des photos est en cause." +msgstr "" + +#: aperodedenis.py:5261 +msgid "Utiliser les items du menu 'outils' pour vérifier ces points." +msgstr "" + +#: aperodedenis.py:5272 +msgid "Pas d'orientation trouvé par tapas." +msgstr "" + +#: aperodedenis.py:5272 +msgid "Pourquoi MicMac s'arrête :" +msgstr "" + +#: aperodedenis.py:5272 +msgid "Prises de vues non positionnées." +msgstr "" + +#: aperodedenis.py:5273 +msgid "Consulter l'aide (quelques conseils)," +msgstr "" + +#: aperodedenis.py:5273 +msgid "consulter la trace." +msgstr "" + +#: aperodedenis.py:5274 +msgid "Verifier la qualité des photos (item du menu outil)" +msgstr "" + +#: aperodedenis.py:5288 +msgid "Calibration incomplète : " +msgstr "" + +#: aperodedenis.py:5318 +msgid ". Lancer MicMac pour reprendre le traitement." +msgstr "" + +#: aperodedenis.py:5318 +msgid "Arrêt après Tapas " +msgstr "" + +#: aperodedenis.py:5319 +msgid "Arrêt aprés Tapas sur demande utilisateur" +msgstr "" + +#: aperodedenis.py:5332 +msgid "Tapas n'a pas généré de nuage de points." +msgstr "" + +#: aperodedenis.py:5333 aperodedenis.py:5340 +msgid "Le traitement ne peut se poursuivre." +msgstr "" + +#: aperodedenis.py:5334 +msgid "" +"Vérifier la qualité des photos, modifier les paramètres et relancer tapioca-" +"tapas" +msgstr "" + +#: aperodedenis.py:5339 +msgid "Pas de masque 3D, ou d'image maîtresse pour Malt." +msgstr "" + +#: aperodedenis.py:5341 +msgid "Définir une image maîtresse" +msgstr "" + +#: aperodedenis.py:5342 +msgid "ou Changer le mode 'GeomImage' qui impose une image maîtresse" +msgstr "" + +#: aperodedenis.py:5343 +msgid "ou définir un masque 3D" +msgstr "" + +#: aperodedenis.py:5344 +msgid "Pour cela utiliser l'item option/Malt ou option/C3DC du menu MicMac" +msgstr "" + +#: aperodedenis.py:5363 +msgid "Le fichier modele3D.ply précédent est renommé en " +msgstr "" + +#: aperodedenis.py:5365 +msgid "erreur renommage ancien modele_3d en " +msgstr "" + +#: aperodedenis.py:5366 +msgid "" +"Le fichier Modele3D.ply précédent n'a pu être renommé. Il sera remplacé." +msgstr "" + +#: aperodedenis.py:5385 +msgid "Fin du traitement MicMac " +msgstr "" + +#: aperodedenis.py:5396 +msgid "Tapas non effectué, lancer Micmac depuis le menu. Etat du chantier = " +msgstr "" + +#: aperodedenis.py:5402 +msgid "Pourquoi MicMac est arrêté :" +msgstr "" + +#: aperodedenis.py:5403 +msgid "Pas d'image maîtresse." +msgstr "" + +#: aperodedenis.py:5404 +msgid "Celle-ci est nécessaire pour l'option choisie geomImage de Malt." +msgstr "" + +#: aperodedenis.py:5405 +msgid "" +"Pour corriger modifier les options de Malt ou choississez un masque 3D avec " +"C3DC." +msgstr "" + +#: aperodedenis.py:5406 +msgid "Corriger." +msgstr "" + +#: aperodedenis.py:5421 +msgid "Erreur copie modele3D.ply" +msgstr "" + +#: aperodedenis.py:5442 +msgid "erreur malt GeomImage copy de nuage en modele3D : " +msgstr "" + +#: aperodedenis.py:5442 aperodedenis.py:5445 aperodedenis.py:5464 +#: aperodedenis.py:5467 +msgid " pour : " +msgstr "" + +#: aperodedenis.py:5445 +msgid "erreur malt GeomImage fusion des nuages en modele3D : " +msgstr "" + +#: aperodedenis.py:5464 +msgid "erreur malt AperoDeDenis copy de nuage en modele3D : " +msgstr "" + +#: aperodedenis.py:5467 +msgid "erreur malt AperoDeDenis fusion des nuages en modele3D : " +msgstr "" + +#: aperodedenis.py:5480 +msgid "Aucune photo choisie. Abandon." +msgstr "" + +#: aperodedenis.py:5484 +msgid "Une seule photo choisie. Abandon." +msgstr "" + +#: aperodedenis.py:5490 +msgid "TRACE DETAILLEE" +msgstr "" + +#: aperodedenis.py:5491 +msgid "TRACE SYNTHETIQUE" +msgstr "" + +#: aperodedenis.py:5493 +msgid "DEBUT DU TRAITEMENT MICMAC à " +msgstr "" + +#: aperodedenis.py:5496 +msgid "Photos choisies :" +msgstr "" + +#: aperodedenis.py:5497 +msgid "Ces photos sont recopiées dans le répertoire du chantier :" +msgstr "" + +#: aperodedenis.py:5553 aperodedenis.py:5559 +msgid "" +"Recherche des points remarquables et des correspondances sur une image de " +"taille %s pixels." +msgstr "" + +#: aperodedenis.py:5557 +msgid "" +"Recherche des points remarquables et des correspondances sur l'image entière." +msgstr "" + +#: aperodedenis.py:5570 +msgid "Une seule photo pour la calibration intrinsèque : insuffisant." +msgstr "" + +#: aperodedenis.py:5574 +msgid "Calibration intrinsèque lancée sur les photos : " +msgstr "" + +#: aperodedenis.py:5588 +msgid "" +"Calibration intrinsèque, pour trouver les réglages de l'appareil photo sur " +"quelques photos" +msgstr "" + +#: aperodedenis.py:5588 +msgid "Recherche d'un point de convergence au centre de l'image." +msgstr "" + +#: aperodedenis.py:5594 +msgid "La calibration intrinsèque n'a pas permis de trouver une orientation." +msgstr "" + +#: aperodedenis.py:5597 +msgid "Calibration intrinsèque effectuée." +msgstr "" + +#: aperodedenis.py:5601 +msgid "" +"Une seule photo pour Tapas sans les photos de calibration : insuffisant." +msgstr "" + +#: aperodedenis.py:5630 +msgid "Recherche l'orientation des prises de vues" +msgstr "" + +#: aperodedenis.py:5642 +msgid "Calibration, pour trouver les réglages intrinsèques de l'appareil photo" +msgstr "" + +#: aperodedenis.py:5642 +msgid "Recherche l'orientation des prises de vue." +msgstr "" + +#: aperodedenis.py:5659 +msgid "" +"Fixe l'orientation (axe,plan et métrique) suivant les options de " +"'calibration'" +msgstr "" + +#: aperodedenis.py:5678 +msgid "Création d'un nuage de points grossier." +msgstr "" + +#: aperodedenis.py:5678 +msgid "Positionne les appareils photos autour du sujet." +msgstr "" + +#: aperodedenis.py:5684 +msgid "ligne avec meta : " +msgstr "" + +#: aperodedenis.py:5685 +msgid "" +"ATTENTION : des metadonnées nécessaires sont absentes des photos. Vérifier " +"l'exif." +msgstr "" + +#: aperodedenis.py:5696 +msgid "Ouverture du nuage de points après Apericloud" +msgstr "" + +#: aperodedenis.py:5699 +msgid "Pas de fichier AperiCloud.ply généré." +msgstr "" + +#: aperodedenis.py:5701 +msgid "" +"Consulter l'aide (quelques conseils),\n" +"Consulter la trace." +msgstr "" + +#: aperodedenis.py:5707 +msgid "Tarama : mosaïque des photos d'aprés les tie points" +msgstr "" + +#: aperodedenis.py:5718 +msgid "" +"Prise en compte des points GPS : nécessite au minimum 3 points, chacun sur 2 " +"photos" +msgstr "" + +#: aperodedenis.py:5720 +msgid "" +"Le nombre minimum de points placés sur les photos n'est pas atteint. Abandon." +msgstr "" + +#: aperodedenis.py:5745 +msgid "Préparation du lancement de Malt" +msgstr "" + +#: aperodedenis.py:5754 +msgid "Photos utiles pour malt GeomImage : " +msgstr "" + +#: aperodedenis.py:5756 +msgid "Malt sur toutes les photos" +msgstr "" + +#: aperodedenis.py:5768 +msgid "Photos utiles pour malt AperoDeDenis : " +msgstr "" + +#: aperodedenis.py:5779 +msgid "Mosaique et masque: " +msgstr "" + +#: aperodedenis.py:5781 +msgid "Mosaique seule : " +msgstr "" + +#: aperodedenis.py:5802 aperodedenis.py:5959 aperodedenis.py:8000 +msgid "ATTENTION : cette procédure est longue : patience !" +msgstr "" + +#: aperodedenis.py:5933 +msgid "lance Tawny" +msgstr "" + +#: aperodedenis.py:5939 +msgid " : voir la trace complète." +msgstr "" + +#: aperodedenis.py:6061 +msgid "Echec du traitement MICMAC" +msgstr "" + +#: aperodedenis.py:6061 +msgid "Pas de fichier %s généré." +msgstr "" + +#: aperodedenis.py:6069 +msgid "Nuage de points %s généré." +msgstr "" + +#: aperodedenis.py:6095 +msgid "Détermine un indice de qualité des photos en mode 'line'" +msgstr "" + +#: aperodedenis.py:6096 aperodedenis.py:6127 +msgid "Le résultat sera inscrit dans le fichier trace synthétique" +msgstr "" + +#: aperodedenis.py:6096 aperodedenis.py:6127 aperodedenis.py:6203 +msgid "Patience..." +msgstr "" + +#: aperodedenis.py:6098 +msgid "Debut de la recherche sur la qualité des photos mode 'Line'." +msgstr "" + +#: aperodedenis.py:6126 +msgid "Détermine un indice de qualité des photos en mode 'All' ou 'MulScale'" +msgstr "" + +#: aperodedenis.py:6129 +msgid "" +"Debut de la recherche sur la qualité des photos, mode 'All' ou 'MulScale'." +msgstr "" + +#: aperodedenis.py:6177 aperodedenis.py:8340 +msgid "Classement des photos par nombre de points homologues :" +msgstr "" + +#: aperodedenis.py:6179 +msgid " score = " +msgstr "" + +#: aperodedenis.py:6179 +msgid "photo " +msgstr "" + +#: aperodedenis.py:6182 aperodedenis.py:8347 +msgid "Aucune photo n'a de point analogue avec une autre." +msgstr "" + +#: aperodedenis.py:6186 +msgid "Qualité des photos suite au traitement : " +msgstr "" + +#: aperodedenis.py:6187 aperodedenis.py:8262 aperodedenis.py:8267 +#: aperodedenis.py:8275 +msgid "Homol" +msgstr "" + +#: aperodedenis.py:6199 +msgid "Fin d'examen de qualité des photos." +msgstr "" + +#: aperodedenis.py:6203 +msgid "Copie des photos dans un répertoire de test." +msgstr "" + +#: aperodedenis.py:6228 +msgid "Créer un nouveau chantier avec les photos : " +msgstr "" + +#: aperodedenis.py:6229 +msgid "Les paramètres de Tapioca/Malt seront optimisés." +msgstr "" + +#: aperodedenis.py:6320 +msgid "Caractéristiques de l'appareil photo : " +msgstr "" + +#: aperodedenis.py:6323 +msgid "fabricant : " +msgstr "" + +#: aperodedenis.py:6327 +msgid "Nom de l'appareil photo inacessible." +msgstr "" + +#: aperodedenis.py:6329 +msgid "Nom de l'appareil photo : " +msgstr "" + +#: aperodedenis.py:6335 +msgid "Pas de focale dans l'exif." +msgstr "" + +#: aperodedenis.py:6337 +msgid "Focale : " +msgstr "" + +#: aperodedenis.py:6340 +msgid "Pas de focale équivalente 35 mm dans l'exif :" +msgstr "" + +#: aperodedenis.py:6340 +msgid "Présence de la taille du capteur dans DicoCamera nécesssaire." +msgstr "" + +#: aperodedenis.py:6343 +msgid "Focale équivalente 35 mm absente de l'exif" +msgstr "" + +#: aperodedenis.py:6345 +msgid "Focale équivalente 35 mm : " +msgstr "" + +#: aperodedenis.py:6348 aperodedenis.py:6449 +msgid "" +"DicoCamera.xml non trouvé : paramètrer au préalable le chemin de MicMac\\bin." +msgstr "" + +#: aperodedenis.py:6352 +msgid "L'appareil est inconnu dans DicoCamera.XML." +msgstr "" + +#: aperodedenis.py:6354 +msgid "L'appareil est connu dans DicoCamera.XML." +msgstr "" + +#: aperodedenis.py:6355 +msgid "Taille du capteur en mm : " +msgstr "" + +#: aperodedenis.py:6361 +msgid "Appareil photo :" +msgstr "" + +#: aperodedenis.py:6383 +msgid "Erreur dans exiftool : " +msgstr "" + +#: aperodedenis.py:6385 +msgid "erreur tagExif : " +msgstr "" + +#: aperodedenis.py:6446 +msgid "Pas trouvé de nom d'appareil photo dans l'exif." +msgstr "" + +#: aperodedenis.py:6452 +msgid "" +"Le fichier DicoCamera.xml contient la taille du capteur pour l'appareil :" +msgstr "" + +#: aperodedenis.py:6453 +msgid "taille = " +msgstr "" + +#: aperodedenis.py:6454 +msgid "Modification non prévue dans cette version de l'outil AperoDeDenis" +msgstr "" + +#: aperodedenis.py:6458 +msgid "Pour l'appareil " +msgstr "" + +#: aperodedenis.py:6463 +msgid "Paramètrer au préalable le chemin de MicMac\\bin." +msgstr "" + +#: aperodedenis.py:6467 +msgid "NomCourt" +msgstr "" + +#: aperodedenis.py:6469 +msgid "tailleEnMM" +msgstr "" + +#: aperodedenis.py:6484 +msgid "Erreur lors de l'écriture de DicoCamera.xml" +msgstr "" + +#: aperodedenis.py:6484 +msgid "Une sauvegarde a été créée : DicoCamerra.xml.sav" +msgstr "" + +#: aperodedenis.py:6487 aperodedenis.py:6494 +msgid "Dimensions du capteur non mis à jour" +msgstr "" + +#: aperodedenis.py:6490 +msgid "Dimensions du capteur mis à jour" +msgstr "" + +#: aperodedenis.py:6504 +msgid "Toutes les focales : " +msgstr "" + +#: aperodedenis.py:6513 +msgid "Saisir une ou plusieurs ligne(s) de commande" +msgstr "" + +#: aperodedenis.py:6515 +msgid "Attention : Le chantier n'existe pas." +msgstr "" + +#: aperodedenis.py:6518 +msgid "" +"Entrer soit une commande MicMac, par exemple : mm3d GCPBascule .*.JPG " +"Arbitrary" +msgstr "" + +#: aperodedenis.py:6519 +msgid "S'il n'y a pas de path sur mm3d entrer le chemin : " +msgstr "" + +#: aperodedenis.py:6520 +msgid "" +"soit une commande du système, par exemple sous windows : del /S /Q Tmp-MM-Dir" +msgstr "" + +#: aperodedenis.py:6521 +msgid "Sous votre responsabilité" +msgstr "" + +#: aperodedenis.py:6539 +msgid "Interface graphique pour lancer les modules de MICMAC." +msgstr "" + +#: aperodedenis.py:6540 +msgid "Utilisable sous Linux, Windows, Mac OS." +msgstr "" + +#: aperodedenis.py:6541 +msgid "Logiciel libre diffusé sous licence CeCILL-B." +msgstr "" + +#: aperodedenis.py:6543 +msgid "" +"La barre de titre présente le nom du chantier et la version de l'outil. Une " +"* indique que le chantier est à sauvegarder." +msgstr "" + +#: aperodedenis.py:6544 +msgid "Menu Fichier :" +msgstr "" + +#: aperodedenis.py:6545 +msgid "" +" - Nouveau chantier : constitution d'un 'chantier' comportant les " +"photos, les options d'exécution de Micmac et" +msgstr "" + +#: aperodedenis.py:6546 +msgid " les résultats des traitements." +msgstr "" + +#: aperodedenis.py:6547 +msgid " Les paramètres du chantier sont conservés dans le fichier " +msgstr "" + +#: aperodedenis.py:6548 +msgid "" +" Enregistrer le chantier crée une arborescence dont la racine est le " +"répertoire des photos et le nom du chantier." +msgstr "" + +#: aperodedenis.py:6549 +msgid "" +" - Ouvrir un chantier : revenir sur un ancien chantier pour le " +"poursuivre ou consulter les résultats." +msgstr "" + +#: aperodedenis.py:6550 +msgid "" +" - Enregistrer le chantier : enregistre le chantier en cours sans " +"l'exécuter." +msgstr "" + +#: aperodedenis.py:6551 +msgid "" +" Une * dans la barre de titre indique que le chantier a été modifié." +msgstr "" + +#: aperodedenis.py:6552 +msgid "" +" Le chantier en cours, même non enregistré, est conservé lors de la " +"fermeture de l'application." +msgstr "" + +#: aperodedenis.py:6553 +msgid " - Renommer le chantier : personnalise le nom du chantier." +msgstr "" + +#: aperodedenis.py:6554 +msgid "" +" Le chantier est déplacé dans l'arborescence en indiquant un chemin " +"absolu ou relatif." +msgstr "" + +#: aperodedenis.py:6555 +msgid "" +" Par exemple : 'D:\\MonPremierChantier' nomme 'MonPremierChantier' " +"sous la racine du disque D." +msgstr "" + +#: aperodedenis.py:6556 +msgid "" +" Attention : le changement de disque n'est pas possible dans cette " +"version de l'outil." +msgstr "" + +#: aperodedenis.py:6557 +msgid "" +" - Exporter le chantier en cours : création d'une archive du chantier, " +"qui permet :" +msgstr "" + +#: aperodedenis.py:6558 +msgid " - de conserver le chantier en l'état, pour y revenir." +msgstr "" + +#: aperodedenis.py:6559 +msgid "" +" - de l'importer sous un autre répertoire, un autre disque, un " +"autre ordinateur, un autre système d'exploitation" +msgstr "" + +#: aperodedenis.py:6560 +msgid " - Importer un chantier :" +msgstr "" + +#: aperodedenis.py:6561 +msgid "" +" - copie le chantier sauvegardé dans un nouvel environnement " +"(ordinateur, système d'exploitation)" +msgstr "" + +#: aperodedenis.py:6562 +msgid "" +" - un exemple d'intérêt : copier un chantier aprés tapas, lancer " +"malt avec des options variées sans perdre l'original." +msgstr "" + +#: aperodedenis.py:6563 +msgid "" +" - Du ménage ! : supprimer les chantiers : chaque chantier crée une " +"arborescence de travail." +msgstr "" + +#: aperodedenis.py:6564 +msgid " Cet item permet de supprimer les répertoires devenus inutiles." +msgstr "" + +#: aperodedenis.py:6565 +msgid "" +" Aprés un message demandant confirmation la suppression est " +"définitive, sans récupération possible :" +msgstr "" + +#: aperodedenis.py:6566 +msgid "" +" toute l'arborescence est supprimée, même les archives exportées." +msgstr "" + +#: aperodedenis.py:6567 +msgid "" +" - Quitter : quitte l'application, le chantier en cours est conservé " +"et sera ouvert lors de la prochaine exécution." +msgstr "" + +#: aperodedenis.py:6568 +msgid "Menu Edition :" +msgstr "" + +#: aperodedenis.py:6569 +msgid "" +" - Afficher l'état du chantier : affiche les paramètres du chantier et " +"son état d'exécution." +msgstr "" + +#: aperodedenis.py:6570 +msgid "" +" Par défaut l'état du chantier est affiché lors du lancement de " +"l'application." +msgstr "" + +#: aperodedenis.py:6571 +msgid "" +" Cet item est utile après un message ou l'affichage d'une trace." +msgstr "" + +#: aperodedenis.py:6572 +msgid "" +" - Plusieurs items permettent de consulter les photos, les traces et " +"les vues 3D du chantier en cours." +msgstr "" + +#: aperodedenis.py:6573 +msgid "" +" Visualiser toutes les photos sélectionnées : visualise les photos" +msgstr "" + +#: aperodedenis.py:6574 +msgid "" +" Visualiser les points GPS : visu des seules " +"photos avec points GPS." +msgstr "" + +#: aperodedenis.py:6575 +msgid "" +" Visualiser le masque 3D : visualise le masque " +"3D" +msgstr "" + +#: aperodedenis.py:6576 +msgid "" +" Visualiser le masque 2D et l'image maitre : visualise le masque " +"2D s'il existe et de l'image maître." +msgstr "" + +#: aperodedenis.py:6577 +msgid "" +" Visualiser la ligne horizontale/verticale : visualise le repère " +"Ox ou Oy." +msgstr "" + +#: aperodedenis.py:6578 +msgid "" +" Visualiser la zone plane : visualise la zone " +"plane" +msgstr "" + +#: aperodedenis.py:6579 +msgid "" +" Visualiser la distance : visualise de la " +"distance et les points associés." +msgstr "" + +#: aperodedenis.py:6581 +msgid "" +" Afficher la trace complete du chantier : visualise la trace " +"complète, standard micmac" +msgstr "" + +#: aperodedenis.py:6582 +msgid "" +" Afficher la trace synthétique du chantier : visualise la trace " +"filtrée par aperoDeDenis, moins bavarde" +msgstr "" + +#: aperodedenis.py:6584 +msgid "" +" Afficher l'image 3D non densifiée : lance l'outil pour " +"ouvrir les .PLY sur l'image 3D produite par Tapas" +msgstr "" + +#: aperodedenis.py:6585 +msgid "" +" Afficher l'image 3D densifiée : lance l'outil pour " +"ouvrir les .PLY sur l'image 3D produite par Malt ou C3DC" +msgstr "" + +#: aperodedenis.py:6587 +msgid "" +" Lister Visualiser les images 3D : liste la pyramide " +"des images 3D, créées à chaque étape de Malt" +msgstr "" + +#: aperodedenis.py:6588 +msgid "" +" Fusionner des images 3D : permet de fusionner " +"plusieurs PLY en un seul" +msgstr "" + +#: aperodedenis.py:6589 +msgid "Menu MicMac :" +msgstr "" + +#: aperodedenis.py:6590 +msgid "" +" - Choisir les photos : permet choisir les photos JPG, GIF, TIF ou BMP " +"pour le traitement." +msgstr "" + +#: aperodedenis.py:6591 +msgid "" +" Remarque : les photos GIF et BMP seront converties en JPG " +"(nécessite la présence de l'outil convert)." +msgstr "" + +#: aperodedenis.py:6592 +msgid "" +" Un EXIF avec la focale utilisée pour la prise de vue est " +"nécessaire : si besoin l'ajouter (menu Outil/ajout exif)." +msgstr "" + +#: aperodedenis.py:6593 +msgid " Remarque : " +msgstr "" + +#: aperodedenis.py:6594 +msgid "" +" Le fichier DicoCamera.xml doit comporter la taille du " +"capteur de l'appareil (voir menu Outils)" +msgstr "" + +#: aperodedenis.py:6595 +msgid "" +" - Options : choisir les options des modules Tapioca, Tapas (nuage non " +"densifié) puis de Malt (nuage densifié) : " +msgstr "" + +#: aperodedenis.py:6596 +msgid "" +" Les options suivantes concernent le calcul du nuage de points NON " +"densifié :" +msgstr "" + +#: aperodedenis.py:6597 +msgid "" +" - Tapioca : options et sous options associées (échelles, " +"fichier xml)" +msgstr "" + +#: aperodedenis.py:6598 +msgid "" +" - Tapas : choix d'un mode de calcul, possibilité " +"d'arrêter le traitement après tapas." +msgstr "" + +#: aperodedenis.py:6599 +msgid "" +" La calibration intrinsèque permet de lancer " +"Tapas sur un premier lot de photos." +msgstr "" + +#: aperodedenis.py:6600 +msgid "" +" Typiquement sur les photos de plus grande " +"focale si il y a 2 focales différentes." +msgstr "" + +#: aperodedenis.py:6601 +msgid "" +" L'arrêt après Tapas est nécessaire pour " +"décrire le masque 2D ou 3D." +msgstr "" + +#: aperodedenis.py:6602 +msgid "" +" Produit une image 3D non densifiée avec " +"position des appareils photos." +msgstr "" + +#: aperodedenis.py:6603 +msgid "" +" - Calibration : définir un axe, une zone plane, une " +"distance pour définir le repère du chantier." +msgstr "" + +#: aperodedenis.py:6604 +msgid "" +" - GPS : définir les points de calage GPS qui permettent " +"de géolocaliser la scène." +msgstr "" + +#: aperodedenis.py:6605 +msgid "" +" Pour être utilisé chaque point, minimum 3, doit " +"être placé sur au moins 2 photos." +msgstr "" + +#: aperodedenis.py:6606 +msgid "" +" Cette option est utilisée pour le nuage de point " +"non densifié ET pour le nuage densifié." +msgstr "" + +#: aperodedenis.py:6607 +msgid "" +" Les 3 options suivantes concernent le calcul du nuage de points " +"densifié :" +msgstr "" + +#: aperodedenis.py:6608 +msgid "" +" - Malt : choix du mode et du niveau de densification." +msgstr "" + +#: aperodedenis.py:6609 +msgid " Si le mode est GeomImage : " +msgstr "" + +#: aperodedenis.py:6610 +msgid "" +" désigner une ou plusieurs images maîtresses" +msgstr "" + +#: aperodedenis.py:6611 +msgid "" +" dessiner si besoin le ou les masques " +"associés." +msgstr "" + +#: aperodedenis.py:6612 +msgid "" +" Seuls les points visibles sur les images " +"maitres seront sur l'image 3D finale." +msgstr "" + +#: aperodedenis.py:6613 +msgid "" +" Le masque limite la zone utile de l'image " +"3D finale." +msgstr "" + +#: aperodedenis.py:6614 +msgid "" +" La molette permet de zoomer et le clic " +"droit maintenu de déplacer l'image." +msgstr "" + +#: aperodedenis.py:6615 +msgid "" +" Supprimer une image maîtresse de la liste " +"réinitialise le masque." +msgstr "" + +#: aperodedenis.py:6616 +msgid "" +" Nombre de photos utiles autour de l'image " +"maîtresse :" +msgstr "" + +#: aperodedenis.py:6617 +msgid "" +" Permet de limiter les recherches aux " +"images entourant chaque image maîtresse." +msgstr "" + +#: aperodedenis.py:6618 +msgid "" +" Choix du niveau de densification final : " +"8,4,2 ou 1." +msgstr "" + +#: aperodedenis.py:6619 +msgid " Le niveau 1 est le plus dense. " +msgstr "" + +#: aperodedenis.py:6620 +msgid "" +" La géométrie est revue à chaque niveau et " +"de plus en plus précise : " +msgstr "" + +#: aperodedenis.py:6621 +msgid "" +" la densification s'accroît, et la " +"géométrie s'affine aussi." +msgstr "" + +#: aperodedenis.py:6622 +msgid "" +" - C3DC : dessiner le masque 3D sur le nuage de points " +"AperiCloud généré par Tapas.." +msgstr "" + +#: aperodedenis.py:6623 +msgid "" +" Les touches fonctions à utiliser sont " +"décrites dans l'onglet." +msgstr "" + +#: aperodedenis.py:6624 +msgid "" +" Le masque limite la zone en 3 dimensions de " +"l'image finale." +msgstr "" + +#: aperodedenis.py:6625 +msgid " L'outil de saisie est issu de micmac." +msgstr "" + +#: aperodedenis.py:6626 +msgid "" +" - GPS : définir les points de calage GPS qui " +"permettent de géolocaliser la scène." +msgstr "" + +#: aperodedenis.py:6627 +msgid "" +" Pour être utilisé chaque point, minimum 3, " +"doit être placé sur au moins 2 photos." +msgstr "" + +#: aperodedenis.py:6628 +msgid "" +" Le bouton 'appliquer' permet de calibrer le " +"modèle non densifié immédiatement." +msgstr "" + +#: aperodedenis.py:6629 +msgid "" +" - Lancer MicMac : enregistre le chantier et lance le traitement avec " +"les options par défaut ou choisies par l'item 'options'." +msgstr "" + +#: aperodedenis.py:6630 +msgid "" +" Relance micmac si l'arrêt a été demandé après tapas." +msgstr "" + +#: aperodedenis.py:6631 +msgid "" +" Lancer micmac bloque les photos et les options du " +"chantier." +msgstr "" + +#: aperodedenis.py:6632 +msgid "" +" Pour débloquer le chantier il faut lancer micmac à " +"nouveau et choisir le débloquage." +msgstr "" + +#: aperodedenis.py:6633 +msgid "" +" Le débloquage permet de relancer Malt sans relancer " +"tapioca/tapas : " +msgstr "" + +#: aperodedenis.py:6634 +msgid "" +" le fichier modele3D.ply est conservé sous un autre " +"nom." +msgstr "" + +#: aperodedenis.py:6635 +msgid "menu Vidéo :" +msgstr "" + +#: aperodedenis.py:6636 +msgid "" +" - Options : indiquer le nom de la camera (GoPro, smartphone...), sa " +"focale, sa focale equivalente 35mm" +msgstr "" + +#: aperodedenis.py:6637 +msgid " et le nombre d'images à conserver par seconde de film" +msgstr "" + +#: aperodedenis.py:6638 +msgid "" +" Le nom permet de faire le lien avec DicoCamera.xml qui contient la " +"taille du capteur." +msgstr "" + +#: aperodedenis.py:6639 +msgid " Les focales seront recopiées dans l'exif des images." +msgstr "" + +#: aperodedenis.py:6640 +msgid "" +" Le nombre d'images par seconde sera utilisé pour la sélection des " +"meilleures images." +msgstr "" + +#: aperodedenis.py:6641 +msgid " Remarque :" +msgstr "" + +#: aperodedenis.py:6642 +msgid "" +" Il faut indiquer dans DicoCamera la taille du capteur " +"effectivement utilisée par la fonction camera," +msgstr "" + +#: aperodedenis.py:6643 +msgid "" +" taille qui peut être inférieure à la taille du capteur utilisée " +"pour les photos." +msgstr "" + +#: aperodedenis.py:6644 +msgid " Voir par exemple pour une camera Gopro :" +msgstr "" + +#: aperodedenis.py:6646 +msgid "" +" - Nouveau chantier : choisir une video : choisir un fichier video " +"issu d'une camera ou d'une GoPro." +msgstr "" + +#: aperodedenis.py:6647 +msgid "" +" La vidéo sera décompactée en images, l'exif sera créé avec les " +"informations en options." +msgstr "" + +#: aperodedenis.py:6648 +msgid "" +" Cette étape nécessite la présence de l'outil ffmpeg sous le " +"répertoire bin de MicMac (dépend de la version de MicMac)." +msgstr "" + +#: aperodedenis.py:6649 +msgid "" +" Un nouveau chantier est créé avec les options suivante : Line pour " +"Tapioca et FishEyeBasic pour Tapas." +msgstr "" + +#: aperodedenis.py:6650 +msgid "" +" - Sélection des images : il est raisonnable de ne garder que quelques " +"images par seconde de film." +msgstr "" + +#: aperodedenis.py:6651 +msgid "" +" Le nombre d'images conservées par seconde est indiqué dans les " +"options." +msgstr "" + +#: aperodedenis.py:6652 +msgid "" +" Chaque seconde de film les 'meilleures' images seront retenues, les " +"autres effacées." +msgstr "" + +#: aperodedenis.py:6653 +msgid "" +" Attention : cette étape n'est pas effective pour toutes les " +"versions de MicMac. La version mercurial 5508 fonctionne." +msgstr "" + +#: aperodedenis.py:6654 +msgid "" +" Une fois les images sélectionnées le chantier est créé : utiliser " +"le menu MicMac comme pour un chantier normal." +msgstr "" + +#: aperodedenis.py:6655 +msgid "menu Outils :" +msgstr "" + +#: aperodedenis.py:6656 +msgid "" +" - Affiche le nom et la focale de l'appareil photo : fabricant, modèle " +"et focale de la première photo." +msgstr "" + +#: aperodedenis.py:6657 +msgid "" +" Il y a 2 types de focales : focale effective et focale équivalente " +"35 mm." +msgstr "" + +#: aperodedenis.py:6658 +msgid "" +" Indique si l'appareil photo est connu dans '/XML MicMac/DicoCamera." +"xml'." +msgstr "" + +#: aperodedenis.py:6659 +msgid "" +" - Affiche toutes les focales des photos : focales et focales " +"equivalentes en 35mm." +msgstr "" + +#: aperodedenis.py:6660 +msgid "" +" Si les focales ne sont pas identiques pour toutes les photos : " +"utiliser la calibration intrinséque de tapas." +msgstr "" + +#: aperodedenis.py:6661 +msgid "" +" - Mettre à jour DicoCamera.xml : ajouter la taille du capteur dans '/" +"XML MicMac/DicoCamera.xml'." +msgstr "" + +#: aperodedenis.py:6662 +msgid "" +" La taille du capteur dans DicoCamera.xml est requise si la focale " +"équivalente 35mm est absente de l'exif." +msgstr "" + +#: aperodedenis.py:6663 +msgid "" +" La taille du capteur facilite les calculs et améliore les résultats." +msgstr "" + +#: aperodedenis.py:6664 +msgid "" +" La taille du capteur se trouve sur le site du fabricant ou sur " +"http://www.dpreview.com." +msgstr "" + +#: aperodedenis.py:6665 +msgid "" +" - Qualité des photos du dernier traitement : calcule le nombre moyen " +"de points homologues par photo." +msgstr "" + +#: aperodedenis.py:6666 +msgid "" +" Si des photos présentent des moyennes très faibles elles peuvent " +"faire échouer le traitement." +msgstr "" + +#: aperodedenis.py:6667 +msgid "" +" - Qualité des photos 'Line' : calcule le nombre moyen de points " +"homologues par photo en mode 'Line', taille 1000." +msgstr "" + +#: aperodedenis.py:6668 +msgid "" +" - Qualité des photos 'MulScale ou All' : calcule le nombre moyen de " +"points homologues par photo, taille 1000.'." +msgstr "" + +#: aperodedenis.py:6669 +msgid "" +" Ce nombre informe sur la qualité relative des photos au sein du " +"chantier." +msgstr "" + +#: aperodedenis.py:6670 +msgid "" +" La présence de photos avec peu de points homologues peut faire " +"échouer le traitement." +msgstr "" + +#: aperodedenis.py:6671 +msgid "" +" Il est parfois préférable de traiter peu de photos mais de bonne " +"qualité." +msgstr "" + +#: aperodedenis.py:6672 +msgid "" +" - Modifier l'exif des photos : permet la création et la modification " +"des exifs des photos du chantier." +msgstr "" + +#: aperodedenis.py:6673 +msgid "menu Paramétrage :" +msgstr "" + +#: aperodedenis.py:6674 +msgid "" +" - Affiche les paramètres : visualise les chemins de micmac\\bin, " +"d'exiftool, du fichier pour visualiser les .ply (Meshlab ou Cloud Compare)," +msgstr "" + +#: aperodedenis.py:6675 +msgid "" +" ainsi que le répertoire où se trouve les fichiers paramètres de " +"l'interface." +msgstr "" + +#: aperodedenis.py:6676 +msgid "" +" Ces paramètres sont sauvegardés de façon permanente dans le " +"fichier :" +msgstr "" + +#: aperodedenis.py:6678 +msgid "" +" - Désigner le répertoire MicMac\\bin : répertoire où se trouvent les " +"modules de MicMac " +msgstr "" + +#: aperodedenis.py:6679 +msgid "" +" Si plusieurs versions sont installées cet item permet de changer " +"facilement la version de MicMac utilisée." +msgstr "" + +#: aperodedenis.py:6680 +msgid "" +" - Désigner l'application exiftool, utile pour modifier les exif (elle " +"se trouve sous micMac\\binaire-aux)." +msgstr "" + +#: aperodedenis.py:6681 +msgid "" +" - Désigner l'application convert d'ImageMagick, utile pour convertir " +"les gif, tif et bmp en jpg (elle se trouve sous micMac\\binaire-aux)." +msgstr "" + +#: aperodedenis.py:6682 +msgid "" +" - Désigner l'application ouvrant les fichiers .PLY. Ce peut être " +"Meshlab, CloudCompare ou autre." +msgstr "" + +#: aperodedenis.py:6683 +msgid " Sous Windows Meshlab se trouve sous un répertoire nommé VCG." +msgstr "" + +#: aperodedenis.py:6684 +msgid " - Activer/désactiver le 'tacky' message de lancement" +msgstr "" + +#: aperodedenis.py:6685 +msgid "menu Aide :" +msgstr "" + +#: aperodedenis.py:6686 +msgid "" +" - Pour commencer : à lire lors de la prise en main de l'interface." +msgstr "" + +#: aperodedenis.py:6687 +msgid " - Aide : le détail des items de menu." +msgstr "" + +#: aperodedenis.py:6688 +msgid " - Quelques conseils : sur la prise de vue et les options." +msgstr "" + +#: aperodedenis.py:6689 +msgid " - Historique : les nouveautés de chaque version." +msgstr "" + +#: aperodedenis.py:6690 +msgid " - A propos" +msgstr "" + +#: aperodedenis.py:6691 +msgid " Quelques précisions :" +msgstr "" + +#: aperodedenis.py:6692 +msgid "" +" Cette version a été développée sous Windows XP et Seven avec micmac rev " +"5508 d'avril 2015." +msgstr "" + +#: aperodedenis.py:6693 +msgid "" +" L'utilisation d'autres versions de Micmac a été testée, jusqu'à la version " +"6219." +msgstr "" + +#: aperodedenis.py:6694 +msgid " Le fonctionnement sous Ubuntu Trusty a été vérifié." +msgstr "" + +#: aperodedenis.py:6695 +msgid " Consulter la documentation de MicMac, outil réalisé par l'IGN." +msgstr "" + +#: aperodedenis.py:6696 +msgid " Consulter le guide d'installation et de prise en main d'AperoDeDenis." +msgstr "" + +#: aperodedenis.py:6705 +msgid "" +"Interface graphique pour lancer les modules de MICMAC : quelques conseils." +msgstr "" + +#: aperodedenis.py:6706 +msgid "Prises de vue :" +msgstr "" + +#: aperodedenis.py:6707 +msgid "" +" - Le sujet doit être immobile durant toutes la séance de " +"prise de vue." +msgstr "" + +#: aperodedenis.py:6708 +msgid "" +" - Le sujet doit être bien éclairé, la prise de vue en plein " +"jour doit être recherchée." +msgstr "" + +#: aperodedenis.py:6709 +msgid "" +" - Les photos doivent être nettes, attention à la profondeur " +"de champ :" +msgstr "" + +#: aperodedenis.py:6710 +msgid "" +" utiliser la plus petite ouverture possible (nombre F le " +"plus grand, par exemple 22)." +msgstr "" + +#: aperodedenis.py:6711 +msgid "" +" - Les photos de personnes ou d'objet en mouvement sont " +"déconseillées" +msgstr "" + +#: aperodedenis.py:6712 +msgid "" +" - Les surfaces lisses ou réfléchissantes sont défavorables." +msgstr "" + +#: aperodedenis.py:6713 +msgid "" +" - Si le sujet est central prendre une photo tous les 20°, " +"soit 9 photos pour un 'demi-tour', 18 pour un tour complet." +msgstr "" + +#: aperodedenis.py:6714 +msgid "" +" - Si le sujet est en 'ligne' le recouvrement entre photos " +"doit être des 2/3." +msgstr "" + +#: aperodedenis.py:6715 +msgid "" +" - Tester la 'qualité' des photos au sein du chantier (voir " +"les items du menu Outils)." +msgstr "" + +#: aperodedenis.py:6716 +msgid "" +" les photos ayant un mauvais score (voir le menu Outils/" +"Qualité des photos 'All') doivent être supprimées du chantier : " +msgstr "" + +#: aperodedenis.py:6717 +msgid "" +" une seule mauvaise photo peut faire échouer le traitement." +msgstr "" + +#: aperodedenis.py:6718 +msgid "" +" - La présence des dimensions du capteur de l'appareil dans " +"DIcoCamera.xml améliore le traitement." +msgstr "" + +#: aperodedenis.py:6719 +msgid "" +" Cette présence est obligatoire si l'exif ne présente pas " +"la focale équivalente 35mm." +msgstr "" + +#: aperodedenis.py:6720 +msgid "" +" Pour ajouter la taille du capteur utiliser le menu " +"'Outils//mettre à jour DicoCamera'." +msgstr "" + +#: aperodedenis.py:6721 +msgid " Précautions : " +msgstr "" + +#: aperodedenis.py:6722 +msgid "" +" Ne pas utiliser la fonction autofocus. Deux focales " +"différentes maximum pour un même chantier." +msgstr "" + +#: aperodedenis.py:6723 +msgid "" +" Si il y a 2 focales différentes utiliser la calibration " +"intrinsèque de Tapas." +msgstr "" + +#: aperodedenis.py:6724 +msgid "" +" Eviter aussi la fonction 'anti tremblement' qui agit en " +"modfiant la position du capteur." +msgstr "" + +#: aperodedenis.py:6725 +msgid "Options :" +msgstr "" + +#: aperodedenis.py:6726 +msgid "" +" - Tapioca : si le sujet est central conserver les paramètres " +"par défaut." +msgstr "" + +#: aperodedenis.py:6727 +msgid "" +" L'échelle est la taille réduite de l'image (en " +"pixels, ou -1 pour l'image entière) pour la recherche des points homologues." +msgstr "" + +#: aperodedenis.py:6728 +msgid "" +" Si le sujet est en ligne choisir 'line' dans les " +"options de Tapioca, " +msgstr "" + +#: aperodedenis.py:6729 +msgid "" +" puis delta = 1, si les " +"photos se recouvrent à moitiè, " +msgstr "" + +#: aperodedenis.py:6730 +msgid "" +" ou delta = 2 voire +, " +"si le recouvrement est plus important." +msgstr "" + +#: aperodedenis.py:6731 +msgid "" +" L'option ALl recherche les points homologues sur " +"toutes les paires de photos (ce qui peut faire beaucoup !)" +msgstr "" + +#: aperodedenis.py:6732 +msgid "" +" L'option MulScale recherche les points homologues " +"en 2 temps :" +msgstr "" + +#: aperodedenis.py:6733 +msgid "" +" 1) sur toutes les paires avec une taille de " +"photo réduite (typiquement 300)" +msgstr "" + +#: aperodedenis.py:6734 +msgid "" +" 2) Seules les paires de photos ayant eu au " +"moins 2 points homologues à cette échelle seront" +msgstr "" + +#: aperodedenis.py:6735 +msgid "" +" retenues pour rechercher les points " +"homologues à la seconde échelle. Gain de temps important possible." +msgstr "" + +#: aperodedenis.py:6736 +msgid "" +" - Tapas : si l'appareil photo est un compact ou un smartphone " +"choisir RadialBasic, " +msgstr "" + +#: aperodedenis.py:6737 +msgid "" +" si l'appareil photo est un reflex haut de gamme " +"choisir RadialExtended " +msgstr "" + +#: aperodedenis.py:6738 +msgid "" +" si l'appareil photo est de moyenne gamme choisir " +"RadialStd" +msgstr "" + +#: aperodedenis.py:6739 +msgid "" +" si les photos ont 2 focales alors choisir toutes " +"celles qui ont la plus grande focale pour la calibration intrinsèque." +msgstr "" + +#: aperodedenis.py:6740 +msgid "" +" L'arrêt aprés Tapas est conseillé : la " +"visualisation du nuage de points non densifié" +msgstr "" + +#: aperodedenis.py:6741 +msgid "" +" permet de définir un masque, 2D ou 3D, pour l'étape " +"suivante." +msgstr "" + +#: aperodedenis.py:6742 +msgid "" +" - Calibration : permet de définir un repère et une métrique " +"(axe, plan et distance, tous obligatoires)." +msgstr "" + +#: aperodedenis.py:6743 +msgid "" +" - Malt : pour le mode GeomImage indiquer une ou plusieurs " +"images maîtresses." +msgstr "" + +#: aperodedenis.py:6744 +msgid "" +" Seuls les points visibles sur ces images seront " +"conservés dans le nuage de points." +msgstr "" + +#: aperodedenis.py:6745 +msgid "" +" Sur ces images maîtresses tracer les masque " +"délimitant la partie 'utile' de la photo." +msgstr "" + +#: aperodedenis.py:6746 +msgid "" +" Le résultat sera mis en couleur suivant les images " +"maitresses." +msgstr "" + +#: aperodedenis.py:6747 +msgid "" +" (éviter trop de recouvrement entre les maîtresses !)." +msgstr "" + +#: aperodedenis.py:6748 +msgid "" +" Le traitement avec masque sera accéléré et le " +"résultat plus 'propre'." +msgstr "" + +#: aperodedenis.py:6749 +msgid "" +" - C3DC : propose de définir un masque en 3D qui conservera " +"tout le volume concerné." +msgstr "" + +#: aperodedenis.py:6750 +msgid "" +" Alternative à Malt, le traitement est beaucoup plus " +"rapide. Nécessite la dernière version de MicMac." +msgstr "" + +#: aperodedenis.py:6751 +msgid "" +" - GPS : définir au moins 3 points cotés et les placer sur 2 " +"photos. La trace indique s'ils sont pris en compte" +msgstr "" + +#: aperodedenis.py:6752 +msgid "Si MicMac ne trouve pas d'orientation ou pas de nuage de points :" +msgstr "" + +#: aperodedenis.py:6753 +msgid "" +" - Examiner la qualité des photos (utiliser le menu outils/" +"Qualité des photos): ." +msgstr "" + +#: aperodedenis.py:6754 +msgid "" +" 1) Eliminer les photos ayant les plus mauvais scores" +msgstr "" + +#: aperodedenis.py:6755 +msgid "" +" 2) si ce n'est pas suffisant ne garder que les " +"meilleures photos (typiquement : moins de 10)" +msgstr "" + +#: aperodedenis.py:6756 +msgid "" +" Penser que des photos floues ou avec un sujet " +"brillant, lisse, mobile, transparent, vivant sont défavorables." +msgstr "" + +#: aperodedenis.py:6757 +msgid "" +" 3) Augmenter l'échelle des photos pour tapioca, " +"mettre -1 au lieu de la valeur par défaut." +msgstr "" + +#: aperodedenis.py:6758 +msgid "" +" 4) modifier le type d'appareil pour Tapas (radialstd " +"ou radialbasic)" +msgstr "" + +#: aperodedenis.py:6759 +msgid "" +" 5) vérifier la taille du capteur dans dicocamera, " +"nécessaire si la focale equivalente 35 mm est absente de l'exif" +msgstr "" + +#: aperodedenis.py:6760 +msgid "" +" 6) examiner la trace synthétique et la trace " +"complète : MicMac donne quelques informations" +msgstr "" + +#: aperodedenis.py:6761 +msgid "" +" 7) consulter le forum micmac (http://forum-micmac." +"forumprod.com)" +msgstr "" + +#: aperodedenis.py:6762 +msgid "" +" 8) faites appel à l'assistance de l'interface (voir " +"adresse dans l'a-propos)" +msgstr "" + +#: aperodedenis.py:6771 +msgid " Pour commencer avec l'interface graphique MicMac :" +msgstr "" + +#: aperodedenis.py:6772 +msgid " Tout d'abord : installer MicMac." +msgstr "" + +#: aperodedenis.py:6773 +msgid "" +" Puis : installer Meshlab ou CloudCompare (pour afficher les nuages de " +"points)" +msgstr "" + +#: aperodedenis.py:6774 +msgid " Ensuite, dans cette interface graphique :" +msgstr "" + +#: aperodedenis.py:6775 +msgid "" +"1) Paramètrer l'interface : indiquer ou se trouvent le répertoire bin de " +"MicMac et l'éxécutable Meshlab ou CloudCompare." +msgstr "" + +#: aperodedenis.py:6776 +msgid "" +" Indiquer éventuellement ou se trouvent exiftool et convert d'ImageMagick " +"(en principe sous MicMac\\binaire-aux)." +msgstr "" + +#: aperodedenis.py:6777 +msgid "" +"2) Choisir quelques photos, par exemple du jeu d'essai gravillons, au moins " +"3 mais pas plus de 6 pour commencer (menu MicMac)." +msgstr "" + +#: aperodedenis.py:6778 +msgid "3) Lancer MicMac en laissant les paramètres par défaut (menu MicMac)." +msgstr "" + +#: aperodedenis.py:6779 +msgid "" +" Si tout va bien une vue en 3D non densifiée doit s'afficher, patience : " +"cela peut être long." +msgstr "" + +#: aperodedenis.py:6780 +msgid "" +"4) Si tout va bien alors modifier les options pour la suite du traitement " +"(Malt ou C3DC) (voir la doc)." +msgstr "" + +#: aperodedenis.py:6781 +msgid " Puis re lancer MicMac pour obtenir une vue 3D densifiée." +msgstr "" + +#: aperodedenis.py:6782 +msgid "" +"5) Si tout ne va pas bien re 'lancer MicMac' et annuler le traitement, puis :" +msgstr "" + +#: aperodedenis.py:6783 +msgid " Lire 'quelques conseils' (menu Aide)." +msgstr "" + +#: aperodedenis.py:6784 +msgid " Tester la qualité des photos (menu Outils)." +msgstr "" + +#: aperodedenis.py:6785 +msgid " Examiner les traces (menu Edition)," +msgstr "" + +#: aperodedenis.py:6786 +msgid " Consulter l'aide (menu Aide)," +msgstr "" + +#: aperodedenis.py:6787 +msgid "" +" Consulter le guide d'installation et de prise en main de l'interface." +msgstr "" + +#: aperodedenis.py:6788 +msgid " Consulter le forum MicMac sur le net, consulter la doc MicMac." +msgstr "" + +#: aperodedenis.py:6789 +msgid "6) Si une solution apparaît : modifier les options (menu MicMac)." +msgstr "" + +#: aperodedenis.py:6790 +msgid " puis relancer le traitement." +msgstr "" + +#: aperodedenis.py:6791 +msgid "" +"7) Si le problème persiste faire appel à l'assistance de l'interface " +"(adresse mail dans l'A-propos)" +msgstr "" + +#: aperodedenis.py:6796 +msgid "Historique des versions diffusées sur le site de l'IGN" +msgstr "" + +#: aperodedenis.py:6798 +msgid "" +"Version 1.5 : première version diffusée sur le site de l'IGN le 23/11/2015." +msgstr "" + +#: aperodedenis.py:6799 +msgid "" +"Version 1.55 : sous Windows le fichier paramètre est placé sous le " +"répertoire APPDATA de l'utilisateur," +msgstr "" + +#: aperodedenis.py:6800 +msgid "" +"ce qui règle les questions relatives aux droits d'accès en écriture. Mise en " +"ligne le 04/12/2015." +msgstr "" + +#: aperodedenis.py:6801 +msgid "Version 1.60 : ajout des fonctions :" +msgstr "" + +#: aperodedenis.py:6802 +msgid "- Qualité des photos lors du dernier traitement" +msgstr "" + +#: aperodedenis.py:6803 +msgid "- Exporter le chantier en cours" +msgstr "" + +#: aperodedenis.py:6804 +msgid "" +"- Importer un chantier (permet de recopier le chantier sur un autre " +"répertoire, disque, ordinateur, système d'exploitation)" +msgstr "" + +#: aperodedenis.py:6805 +msgid "- Les fichiers 'trace' sont enregistrés au format utf-8." +msgstr "" + +#: aperodedenis.py:6806 +msgid "Version 2.00 : ajout des fonctions :" +msgstr "" + +#: aperodedenis.py:6807 +msgid "- Choix de photos pour la calibration intrinsèque par Tapas." +msgstr "" + +#: aperodedenis.py:6808 +msgid "" +"- Possibilité de relancer Malt sans relancer Tapioca/Tapas tout en " +"conservant les images 3D générées." +msgstr "" + +#: aperodedenis.py:6809 +msgid "" +"- Conservation de plusieurs fichiers modele3D.ply après Malt pour un même " +"chantier." +msgstr "" + +#: aperodedenis.py:6810 +msgid "" +"- Choix du niveau de zoom d'arrêt de la procédure Malt : de 1 (par défaut) à " +"8." +msgstr "" + +#: aperodedenis.py:6811 +msgid "" +"- Création de tous les fichiers .ply correspondants à tous les niveaux de " +"zoom calculés." +msgstr "" + +#: aperodedenis.py:6812 +msgid "" +"- Ajout d'un item du menu édition listant et visualisant toutes les images " +"3D générées." +msgstr "" + +#: aperodedenis.py:6813 +msgid "" +"- Choix du nombre de photos à retenir autour de l'image maître pour Malt." +msgstr "" + +#: aperodedenis.py:6814 +msgid "" +"- Traitement des vidéos (par exemple GoPro) : décompactage, sélection, mise " +"à jour de l'exif" +msgstr "" + +#: aperodedenis.py:6815 +msgid "" +"- Ajout de deux contrôles sur le lot des photos : mêmes dimensions, même " +"focale." +msgstr "" + +#: aperodedenis.py:6816 +msgid "- Ajout d'un item 'historique' dans le menu Aide." +msgstr "" + +#: aperodedenis.py:6817 +msgid "- Ajout d'un item du menu édition fusionnant les images 3D." +msgstr "" + +#: aperodedenis.py:6817 +msgid "Version 2.10" +msgstr "" + +#: aperodedenis.py:6818 +msgid "- Plusieurs images maîtresses, plusieurs masques." +msgstr "" + +#: aperodedenis.py:6819 +msgid "- Conversion automatique des fichiers PNG, BMP, GIF, TIF en JPG" +msgstr "" + +#: aperodedenis.py:6820 +msgid "" +"- Ajout d'un item du menu Outils permettant de modifier les exifs. Diffusion " +"restreinte à la DTer NC le 16/02/2016" +msgstr "" + +#: aperodedenis.py:6821 +msgid "" +"- Maintien des options compatibles lors du choix de nouvelles photos. " +"Février 2016" +msgstr "" + +#: aperodedenis.py:6821 +msgid "Version 2.20 :" +msgstr "" + +#: aperodedenis.py:6822 +msgid "Version 2.30 : " +msgstr "" + +#: aperodedenis.py:6823 +msgid "- Modification des options par défaut dans le menu outils." +msgstr "" + +#: aperodedenis.py:6824 +msgid "- Choix de l'option (Statue ou QuickMac) pour C3DC. Avril 2016" +msgstr "" + +#: aperodedenis.py:6824 +msgid "Version 2.40 :" +msgstr "" + +#: aperodedenis.py:6825 +msgid "" +"- Référentiel GPS calculé après Tapas (et toujours avant Malt). La virgule " +"est un séparateur décimal accepté." +msgstr "" + +#: aperodedenis.py:6825 +msgid "Version 2.45 :" +msgstr "" + +#: aperodedenis.py:6826 +msgid "" +"- Possiblité d'appliquer la calibration GPS sans relancer malt. Mai 2016" +msgstr "" + +#: aperodedenis.py:6827 +msgid "" +"- Ajout de Tawny aprés Malt en mode Ortho, désactivation du message de " +"lancement. Juin 2016" +msgstr "" + +#: aperodedenis.py:6827 +msgid "Version 2.50 :" +msgstr "" + +#: aperodedenis.py:6828 +msgid "- Version bilingue Français/Anglais. Octobre 2016" +msgstr "" + +#: aperodedenis.py:6828 +msgid "Version 3.00 :" +msgstr "" + +#: aperodedenis.py:6829 +msgid "- Choix des N meilleures photos pour un nouveau dossier. Novembre 2016" +msgstr "" + +#: aperodedenis.py:6829 +msgid "Version 3.10 :" +msgstr "" + +#: aperodedenis.py:6830 +msgid "Version 3.20 :" +msgstr "" + +#: aperodedenis.py:6830 +msgid "janvier 2017" +msgstr "" + +#: aperodedenis.py:6831 +msgid "" +"- Ajout d'un choix pour Malt : AperoDeDenis, l'interface recherche pour vous " +"les maîtresses et les photos correspondantes" +msgstr "" + +#: aperodedenis.py:6832 +msgid "" +"- Item de sélection des meilleures images pour créer un nouveau chantier. " +"janvier 2017" +msgstr "" + +#: aperodedenis.py:6833 +msgid "- Possibilité de saisir une unité avec la distance." +msgstr "" + +#: aperodedenis.py:6834 +msgid "- Lancement de Tapas accéléré : suppression du controle des photos" +msgstr "" + +#: aperodedenis.py:6835 +msgid "" +"- Les photos autour de la maîtresse pour Malt sont choisies parmi les " +"meilleures en correspondances" +msgstr "" + +#: aperodedenis.py:6836 +msgid "- Controle affiné des points GPS, message informatif détaillé" +msgstr "" + +#: aperodedenis.py:6837 +msgid "- Possibilité de supprimer UN seul point GPS sur une photo" +msgstr "" + +#: aperodedenis.py:6847 +msgid "Laboratoire Régional de Rouen" +msgstr "" + +#: aperodedenis.py:6847 +msgid "Réalisation Denis Jouin 2015-2016" +msgstr "" + +#: aperodedenis.py:6848 +msgid "Direction Territoriale Normandie Centre" +msgstr "" + +#: aperodedenis.py:6864 +msgid "erreur canvas logo cerema : " +msgstr "" + +#: aperodedenis.py:6948 +msgid "erreur sauveParamChantier : " +msgstr "" + +#: aperodedenis.py:6976 +msgid "erreur sauveParamMicMac : " +msgstr "" + +#: aperodedenis.py:6977 +msgid "" +"L'interface doit être installée dans un répertoire ou vous avez les droits " +"d'écriture." +msgstr "" + +#: aperodedenis.py:6978 +msgid "" +"Installer l'interface AperoDeDenis à un emplacement ou vous avez ce droit." +msgstr "" + +#: aperodedenis.py:6979 +msgid "Répertoire actuel : " +msgstr "" + +#: aperodedenis.py:6980 +msgid "Erreur rencontrée : " +msgstr "" + +#: aperodedenis.py:6981 +msgid "Problème d'installation" +msgstr "" + +#: aperodedenis.py:7018 +msgid "Erreur restauration param généraux : " +msgstr "" + +#: aperodedenis.py:7106 +msgid "Erreur restauration param chantier : " +msgstr "" + +#: aperodedenis.py:7116 +msgid "erreur définir fichier trace, est normale lors d'une importation." +msgstr "" + +#: aperodedenis.py:7287 +msgid "Enregistrer les options saisies ?" +msgstr "" + +#: aperodedenis.py:7287 +msgid "Fermer les options." +msgstr "" + +#: aperodedenis.py:7287 aperodedenis.py:7300 aperodedenis.py:7312 +msgid "abandon" +msgstr "" + +#: aperodedenis.py:7287 aperodedenis.py:7300 aperodedenis.py:7312 +msgid "enregistrer" +msgstr "" + +#: aperodedenis.py:7300 +msgid "Enregistrer les options vidéos saisies ?" +msgstr "" + +#: aperodedenis.py:7300 +msgid "Fermer les options vidéo." +msgstr "" + +#: aperodedenis.py:7312 +msgid "Enregistrer les valeurs saisies ?" +msgstr "" + +#: aperodedenis.py:7312 +msgid "Fermer la modification des exifs." +msgstr "" + +#: aperodedenis.py:7333 +msgid "erreur connexion internet : " +msgstr "" + +#: aperodedenis.py:7349 +msgid "Nouvelle version de l'interface AperoDeDenis" +msgstr "" + +#: aperodedenis.py:7350 +msgid "Nouvelle version : " +msgstr "" + +#: aperodedenis.py:7352 +msgid "Téléchargement à l'adresse : " +msgstr "" + +#: aperodedenis.py:7354 aperodedenis.py:7644 aperodedenis.py:9097 +msgid "OK" +msgstr "" + +#: aperodedenis.py:7355 +msgid "Accéder au site" +msgstr "" + +#: aperodedenis.py:7356 +msgid "Ne plus me le rappeler" +msgstr "" + +#: aperodedenis.py:7371 +msgid "Tous les chantiers sont déjà supprimés." +msgstr "" + +#: aperodedenis.py:7379 +msgid "Chantiers à supprimer" +msgstr "" + +#: aperodedenis.py:7383 +msgid "repertoires" +msgstr "" + +#: aperodedenis.py:7388 aperodedenis.py:7395 +msgid "Suppression des répertoires de travail superflus" +msgstr "" + +#: aperodedenis.py:7389 +msgid "Le répertoire suivant va être supprimé, sans mise en corbeille :" +msgstr "" + +#: aperodedenis.py:7390 +msgid "Confirmez" +msgstr "" + +#: aperodedenis.py:7394 +msgid "ATTENTION : le chantier en cours va être supprimé." +msgstr "" + +#: aperodedenis.py:7396 +msgid "Vont être supprimés les répertoires suivants, sans mise en corbeille :" +msgstr "" + +#: aperodedenis.py:7397 +msgid "Confimez" +msgstr "" + +#: aperodedenis.py:7400 +msgid "Suppression en cours...." +msgstr "" + +#: aperodedenis.py:7405 +msgid "Le précédent chantier %s est en cours de suppression." +msgstr "" + +#: aperodedenis.py:7421 +msgid "Repertoires supprimés :" +msgstr "" + +#: aperodedenis.py:7421 aperodedenis.py:7423 +msgid "Compte rendu de la suppression :" +msgstr "" + +#: aperodedenis.py:7423 +msgid "Aucun répertoire supprimé." +msgstr "" + +#: aperodedenis.py:7426 +msgid "Tous les chantiers demandés sont supprimés." +msgstr "" + +#: aperodedenis.py:7428 +msgid "Il reste un chantier impossible à supprimer maintenant : " +msgstr "" + +#: aperodedenis.py:7430 +msgid "Il reste des chantiers impossibles à supprimer maintenant : " +msgstr "" + +#: aperodedenis.py:7436 +msgid "Choisir" +msgstr "" + +#: aperodedenis.py:7436 +msgid "Choisir : " +msgstr "" + +#: aperodedenis.py:7506 +msgid " : lancement de " +msgstr "" + +#: aperodedenis.py:7515 +msgid "erreur lors de l'éxécution de la commande :" +msgstr "" + +#: aperodedenis.py:7516 aperodedenis.py:7524 aperodedenis.py:7546 +msgid " : fin de " +msgstr "" + +#: aperodedenis.py:7523 +msgid "erreur lors de l'éxécution de la commande." +msgstr "" + +#: aperodedenis.py:7539 +msgid "erreur lecture output : " +msgstr "" + +#: aperodedenis.py:7561 +msgid "Trace complète" +msgstr "" + +#: aperodedenis.py:7562 +msgid "Trace synthétique" +msgstr "" + +#: aperodedenis.py:7565 +msgid "Choix des photos :" +msgstr "" + +#: aperodedenis.py:7566 +msgid "répertoire du chantier :" +msgstr "" + +#: aperodedenis.py:7567 +msgid "Version MicMac : " +msgstr "" + +#: aperodedenis.py:7625 +msgid "erreur ecritureTraceMicMac : " +msgstr "" + +#: aperodedenis.py:7641 +msgid "Choisir une photo" +msgstr "" + +#: aperodedenis.py:7642 +msgid "Cliquer pour choisir une ou plusieurs photos : " +msgstr "" + +#: aperodedenis.py:7650 +msgid "Pas de photos pour cette demande." +msgstr "" + +#: aperodedenis.py:7662 +msgid "Dossier corrompu. Traitement interrompu." +msgstr "" + +#: aperodedenis.py:7662 +msgid "Les fichiers suivants sont absents du disque :" +msgstr "" + +#: aperodedenis.py:7761 +msgid "Options GoPro modifiées" +msgstr "" + +#: aperodedenis.py:7773 +msgid "Abandon : options GoPro inchangées." +msgstr "" + +#: aperodedenis.py:7791 +msgid "" +"L'outil ffmpeg n'est pas installé sur votre ordinateur. Traitement des vidéo " +"GoPro impossible." +msgstr "" + +#: aperodedenis.py:7798 +msgid "" +"Choisir la video issue d'un appareil %(GoProMaker)s %(GoProName)s (sinon " +"modifier les options)" +msgstr "" + +#: aperodedenis.py:7800 +msgid "Video" +msgstr "" + +#: aperodedenis.py:7804 +msgid "" +"Abandon, aucune sélection,\n" +" le chantier reste inchangé." +msgstr "" + +#: aperodedenis.py:7808 +msgid "" +"La version actuelle ne traite que les videos au format MP4, or le format des " +"photos est %s. Désolé." +msgstr "" + +#: aperodedenis.py:7827 +msgid "Décompacte la vidéo" +msgstr "" + +#: aperodedenis.py:7832 +msgid "Il convient de l'associer." +msgstr "" + +#: aperodedenis.py:7832 +msgid "L'outil ffmpeg est absent." +msgstr "" + +#: aperodedenis.py:7839 +msgid "Aucune image décompactée : consulter la trace." +msgstr "" + +#: aperodedenis.py:7866 +msgid "Les images de la video sont décompactées sous le répertoire :" +msgstr "" + +#: aperodedenis.py:7867 +msgid "Il y a %s images décompactées." +msgstr "" + +#: aperodedenis.py:7868 +msgid "" +"Lancer 'Sélection des images' pour sélectionner %s images par seconde de " +"film." +msgstr "" + +#: aperodedenis.py:7869 +msgid "La sélection choisira les 'meilleures' images" +msgstr "" + +#: aperodedenis.py:7870 +msgid "" +"Les options Tapioca et Tapas ont été positionnées pour des images GoPro : " +"modifier si besoin" +msgstr "" + +#: aperodedenis.py:7880 +msgid "met à jour l'exif des JPG décompactés :" +msgstr "" + +#: aperodedenis.py:7914 +msgid "Cette sélection de photos est réservé aux chantiers vidéos" +msgstr "" + +#: aperodedenis.py:7923 aperodedenis.py:7961 +msgid "Sélection d'un sous ensemble des images GoPro décompactées." +msgstr "" + +#: aperodedenis.py:7935 aperodedenis.py:7974 +msgid " a supprimer : " +msgstr "" + +#: aperodedenis.py:7943 +msgid "" +"Aucune sélection effectuée. La version de micmac ne propose peut-être pas " +"cette fonction." +msgstr "" + +#: aperodedenis.py:7943 +msgid "Vous pouvez utiliser le menu 'outils/qualité des photos line'" +msgstr "" + +#: aperodedenis.py:7943 +msgid "puis effectuer une sélection manuelle." +msgstr "" + +#: aperodedenis.py:7943 aperodedenis.py:7982 aperodedenis.py:8303 +#: aperodedenis.py:8439 aperodedenis.py:8457 +msgid "Consulter la trace." +msgstr "" + +#: aperodedenis.py:7945 aperodedenis.py:7984 +msgid "Images sélectionnées." +msgstr "" + +#: aperodedenis.py:7945 aperodedenis.py:7984 +msgid "Vous pouvez lancer Micmac." +msgstr "" + +#: aperodedenis.py:7952 +msgid "Cette sélection de photos est réservé aux chantiers photos" +msgstr "" + +#: aperodedenis.py:7982 +msgid "Aucune sélection effectuée." +msgstr "" + +#: aperodedenis.py:7982 +msgid "" +"Vous pouvez utiliser le menu 'outils/qualité des photos line'\n" +"puis effectuer une sélection manuelle." +msgstr "" + +#: aperodedenis.py:8022 +msgid "Trouvé : " +msgstr "" + +#: aperodedenis.py:8024 +msgid "Non trouvé : " +msgstr "" + +#: aperodedenis.py:8044 +msgid " Pas de fichier pour " +msgstr "" + +#: aperodedenis.py:8063 +msgid "erreur infobulle : " +msgstr "" + +#: aperodedenis.py:8110 +msgid "Aucun point placé sur cette photo" +msgstr "" + +#: aperodedenis.py:8112 +msgid "Un point placé sur cette photo" +msgstr "" + +#: aperodedenis.py:8114 +msgid " points placés sur cette photo" +msgstr "" + +#: aperodedenis.py:8180 +msgid "Aucun chantier mémorisé." +msgstr "" + +#: aperodedenis.py:8188 +msgid "Choisir le chantier à ouvrir :" +msgstr "" + +#: aperodedenis.py:8190 +msgid "vertical" +msgstr "" + +#: aperodedenis.py:8191 +msgid "horizontal" +msgstr "" + +#: aperodedenis.py:8211 +msgid "Ouvrir" +msgstr "" + +#: aperodedenis.py:8216 +msgid " le fichier %s est absent." +msgstr "" + +#: aperodedenis.py:8216 +msgid "Il y a des chantiers incomplets," +msgstr "" + +#: aperodedenis.py:8217 +msgid "Ces chantiers ne peuvent être ouverts mais peuvent être supprimés :" +msgstr "" + +#: aperodedenis.py:8242 +msgid "Abandon utilisateur." +msgstr "" + +#: aperodedenis.py:8262 aperodedenis.py:8279 +msgid "HomolTemporaire" +msgstr "" + +#: aperodedenis.py:8264 +msgid "erreur renommage Homol en HomolTemporaire : " +msgstr "" + +#: aperodedenis.py:8269 +msgid "erreur renommage %s en Homol : " +msgstr "" + +#: aperodedenis.py:8277 +msgid "erreur renommage Homol en : %s : " +msgstr "" + +#: aperodedenis.py:8281 +msgid "erreur renommage HomolTemporaire en Homol : " +msgstr "" + +#: aperodedenis.py:8292 +msgid "dernier traitement : " +msgstr "" + +#: aperodedenis.py:8300 +msgid "Lancer MicMac avant de pouvoir évaluer la qualité des photos." +msgstr "" + +#: aperodedenis.py:8303 +msgid "Le traitement n'a donné aucun point homologue." +msgstr "" + +#: aperodedenis.py:8341 +msgid "Photo" +msgstr "" + +#: aperodedenis.py:8341 +msgid "nb photos en correspondance" +msgstr "" + +#: aperodedenis.py:8341 +msgid "score" +msgstr "" + +#: aperodedenis.py:8349 +msgid " : fin de la recherche sur la qualité des photos." +msgstr "" + +#: aperodedenis.py:8365 +msgid "Lancer d'abord Tapioca/Tapas" +msgstr "" + +#: aperodedenis.py:8393 aperodedenis.py:8410 +msgid "Aucun nuage de points dans ce chantier." +msgstr "" + +#: aperodedenis.py:8396 +msgid "Liste des nuages de points du chantier" +msgstr "" + +#: aperodedenis.py:8397 +msgid "les nuages (fichiers ply) :" +msgstr "" + +#: aperodedenis.py:8398 +msgid "Visualiser" +msgstr "" + +#: aperodedenis.py:8413 +msgid "Fusion de nuages" +msgstr "" + +#: aperodedenis.py:8414 +msgid "Choisir les fichiers à fusionner :" +msgstr "" + +#: aperodedenis.py:8415 +msgid "Fusionner et visualiser" +msgstr "" + +#: aperodedenis.py:8421 aperodedenis.py:8436 +msgid "Choisir au moins 2 nuages pour la fusion." +msgstr "" + +#: aperodedenis.py:8439 +msgid "Les ply attendus n'ont pas été créé." +msgstr "" + +#: aperodedenis.py:8454 +msgid "Nuage fusionné :" +msgstr "" + +#: aperodedenis.py:8454 +msgid "ajouté à la liste des nuages." +msgstr "" + +#: aperodedenis.py:8454 +msgid "résultat de la fusion de :" +msgstr "" + +#: aperodedenis.py:8457 +msgid "La fusion n'a pu se réaliser." +msgstr "" + +#: aperodedenis.py:8467 aperodedenis.py:8487 aperodedenis.py:8526 +#: aperodedenis.py:8540 aperodedenis.py:8574 +msgid "Saisir une valeur numérique" +msgstr "" + +#: aperodedenis.py:8473 aperodedenis.py:8493 aperodedenis.py:8546 +msgid "Passage en coordonnées xyz" +msgstr "" + +#: aperodedenis.py:8475 aperodedenis.py:8478 aperodedenis.py:8495 +#: aperodedenis.py:8548 +msgid "Création de la grille ..." +msgstr "" + +#: aperodedenis.py:8503 aperodedenis.py:8553 +msgid "Le calcul peut durer quelques minutes ..." +msgstr "" + +#: aperodedenis.py:8509 +msgid "Rugosité moyenne quadratique : " +msgstr "" + +#: aperodedenis.py:8510 +msgid "Tortuosité moyenne : " +msgstr "" + +#: aperodedenis.py:8511 aperodedenis.py:8559 +msgid "nombre de profils utilisés : " +msgstr "" + +#: aperodedenis.py:8512 aperodedenis.py:8521 aperodedenis.py:8528 +#: aperodedenis.py:8560 aperodedenis.py:8569 aperodedenis.py:8576 +msgid "id profil entre : " +msgstr "" + +#: aperodedenis.py:8520 aperodedenis.py:8568 +msgid "Choisir une valeur valide " +msgstr "" + +#: aperodedenis.py:8557 +msgid "Profondeur moyenne de profil (moyenne) : " +msgstr "" + +#: aperodedenis.py:8558 +msgid "Profondeur de texture équivalente : " +msgstr "" + +#: aperodedenis.py:8586 +msgid "Le programme de conversion n'est pas présent." +msgstr "" + +#: aperodedenis.py:8612 +msgid "Paramètres mis à jour" +msgstr "" + +#: aperodedenis.py:8613 +msgid "Méthode = " +msgstr "" + +#: aperodedenis.py:8614 +msgid "Pas du maillage = " +msgstr "" + +#: aperodedenis.py:8661 +msgid "Exifs mis à jour" +msgstr "" + +#: aperodedenis.py:8662 +msgid "Fabricant = " +msgstr "" + +#: aperodedenis.py:8663 +msgid "Modèle = " +msgstr "" + +#: aperodedenis.py:8664 +msgid "Focale = " +msgstr "" + +#: aperodedenis.py:8665 +msgid "Focale eq 35mm = " +msgstr "" + +#: aperodedenis.py:8669 +msgid "Abandon de la mise à jour des exifs" +msgstr "" + +#: aperodedenis.py:8679 +msgid "Aucune photo à mettre à jour." +msgstr "" + +#: aperodedenis.py:8682 +msgid "" +"La liste des fichiers comporte plusieurs extensions différentes : abandon." +msgstr "" + +#: aperodedenis.py:8687 +msgid "" +"La version actuelle ne traite que les exif des photos au format JPG, or le " +"format des photos est %s. Désolé, abandon." +msgstr "" + +#: aperodedenis.py:8693 +msgid "Le fichier %s n'existe pas. Abandon" +msgstr "" + +#: aperodedenis.py:8697 +msgid "met à jour l'exif de " +msgstr "" + +#: aperodedenis.py:8723 +msgid "Choisir des photos au préalable." +msgstr "" + +#: aperodedenis.py:8727 +msgid "Attention les photos suivantes sont absentes sur disque : " +msgstr "" + +#: aperodedenis.py:8727 +msgid "Elles sont supprimées." +msgstr "" + +#: aperodedenis.py:8732 +msgid "Problème de fichiers" +msgstr "" + +#: aperodedenis.py:8736 +msgid "Bonjour !" +msgstr "" + +#: aperodedenis.py:8736 +msgid "Commencer par indiquer où se trouve MicMac :" +msgstr "" + +#: aperodedenis.py:8737 +msgid " - menu Paramétrage/Associer le répertoire bin de MicMac" +msgstr "" + +#: aperodedenis.py:8738 +msgid "Ensuite consulter l'aide, item 'pour commencer'." +msgstr "" + +#: aperodedenis.py:8739 +msgid "Si besoin :" +msgstr "" + +#: aperodedenis.py:8740 +msgid "" +" - Associer convert et exiftool s'ils ne sont pas trouvés automatiquement " +"sous micmac/binaire-aux" +msgstr "" + +#: aperodedenis.py:8741 +msgid "" +" - Associer un outil (CloudCompare ou Meshlab) pour afficher les nuages de " +"points 3D" +msgstr "" + +#: aperodedenis.py:8742 +msgid " - Consulter la notice d'installation et de prise en main" +msgstr "" + +#: aperodedenis.py:8753 +msgid "Désigner le fichier convert, ou avconv, d'image Magick" +msgstr "" + +#: aperodedenis.py:8753 +msgid "en principe sous micmac\\binaire-aux (menu paramétrage)." +msgstr "" + +#: aperodedenis.py:8758 +msgid "" +"Désigner le fichier ffmpeg (possible sous micmac\\binaire-aux (menu " +"paramétrage)." +msgstr "" + +#: aperodedenis.py:8775 +msgid "Revenir aux options par défaut d'AperoDeDenis" +msgstr "" + +#: aperodedenis.py:8776 aperodedenis.py:8794 +msgid "Utiliser les options du chantier en cours" +msgstr "" + +#: aperodedenis.py:8777 aperodedenis.py:8795 +msgid "Ne rien changer" +msgstr "" + +#: aperodedenis.py:8780 +msgid "Options par défaut réinitialisées" +msgstr "" + +#: aperodedenis.py:8784 aperodedenis.py:8799 +msgid "Les options par défaut seront désormais celles du chantier en cours" +msgstr "" + +#: aperodedenis.py:8793 +msgid "" +"Les options par défaut actuelles sont les options par défaut d'AperoDeDenis" +msgstr "" + +#: aperodedenis.py:8808 +msgid "" +"Options par défaut non sauvegardées car les options du chantier en cours " +"sont invalides :" +msgstr "" + +#: aperodedenis.py:8834 +msgid "erreur sauveOptions : " +msgstr "" + +#: aperodedenis.py:8835 +msgid "Erreur rencontrée lors de la sauvegarde des options : " +msgstr "" + +#: aperodedenis.py:8864 +msgid "erreur restauration options : " +msgstr "" + +#: aperodedenis.py:8903 +msgid "fin normale d'aperodedenis." +msgstr "" + +#: aperodedenis.py:8921 +msgid "fonction" +msgstr "" + +#: aperodedenis.py:8922 +msgid "valeur en retour : " +msgstr "" + +#: aperodedenis.py:8925 +msgid "variable" +msgstr "" + +#: aperodedenis.py:8926 +msgid "valeur : " +msgstr "" + +#: aperodedenis.py:8927 +msgid "Détail de la %(typeVar)s : %(nomVar)s" +msgstr "" + +#: aperodedenis.py:8928 +msgid "Identifiant : " +msgstr "" + +#: aperodedenis.py:8929 +msgid "Type : " +msgstr "" + +#: aperodedenis.py:8930 +msgid "class = " +msgstr "" + +#: aperodedenis.py:8931 +msgid "Les attributs : " +msgstr "" + +#: aperodedenis.py:8939 +msgid "Erreur suppression fichier :" +msgstr "" + +#: aperodedenis.py:8962 +msgid "erreur ajout : " +msgstr "" + +#: aperodedenis.py:8977 +msgid "erreur remove = " +msgstr "" + +#: aperodedenis.py:9003 +msgid "erreur zip = " +msgstr "" + +#: aperodedenis.py:9035 +msgid "erreur mercurial : %(e)s pour mm3D=%(mm3D)s" +msgstr "" + +#: aperodedenis.py:9036 +msgid "pas de version identifiée de MicMac" +msgstr "" + +#: aperodedenis.py:9085 +msgid "Nouveau nom pour le chantier : " +msgstr "" + +#: aperodedenis.py:9121 +msgid "Console" +msgstr "" + +#: aperodedenis.py:9238 +msgid "Question" +msgstr "" diff --git a/InterfaceCEREMA/readme.txt b/InterfaceCEREMA/readme.txt new file mode 100644 index 0000000..b596031 --- /dev/null +++ b/InterfaceCEREMA/readme.txt @@ -0,0 +1,25 @@ +L'interface CEREMA offre une interface graphique conviviale pour +MICMAC, l'outil de photogrammétrie libre de l'IGN. + +Préalable : + +L'application MicMac de l'IGN doit être installée ( http://logiciels.ign.fr/?Micmac ) + +---------------------------------------------------- + +Installation de l'interface CEREMA sous Windows 64 bits ou 32 bitss: + +Utiliser l'installateur windows .msi + +---------------------------------------------------- + +Installation de l'interface CEREMA sous Linux ou Ubuntu : + +utiliser les installateurs .deb ou .rpm + +---------------------------------------------------- + +Installation sous les autres systèmes (mac) : + +voir la documentation +