Upload files to "Python Files"

This commit is contained in:
piair 2024-02-16 13:26:43 +01:00
parent 94ea9b1a5a
commit 4e0c175bdc
4 changed files with 770 additions and 0 deletions

BIN
Python Files/images.py Normal file

Binary file not shown.

100
Python Files/kmoy.py Normal file
View File

@ -0,0 +1,100 @@
from PIL import Image, ImageOps
import numpy as np
import random as rd
import math
# Lecture de l'image et changement du contraste
image = Image.open("./images/2.jpg",mode = 'r')
image = ImageOps.autocontrast(image, cutoff=10)
im = np.asarray(image)
nb_lignes, nb_colones, nb_subpixel = np.shape(im) # nb_subpixel est le nombre d'élements d'un points (R, G, B) = 3
classe = [[-1 for i in range(nb_colones)] for j in range(nb_lignes)] # Tableau des classes de chaque éléments
nb_classe = 8
# initialisation centres
centres = []
for i in range(nb_classe) :
ir = rd.randint(0,nb_lignes-1)
jr = rd.randint(0,nb_colones-1)
while [im[ir,jr,s] for s in range(nb_subpixel)] in centres :
ir = rd.randint(0,nb_lignes-1)
jr = rd.randint(0,nb_colones-1)
centres.append([im[ir,jr,s] for s in range(nb_subpixel)]) # On prend des pixels aléatoires dans l'image, et on vérifie qu'ils sont tous differents
# distance (voire pour prendre plus efficace ?)
def distance(e1: list, e2: list) : # distance entre deux couleurs
d = len(e1)
res = 0
for i in range(d) :
res = max(res,(e1[i]-e2[i])**2)
return(res)
# ranger au plus proche des centres
def classer() : # permet de classer les elements dans chaque classe
global classe, im, nb_lignes, nb_colones, centres
b = False
for i in range(nb_lignes) : # On parcours toute l'image
for j in range(nb_colones) : # --
dmin = 0
if classe[i][j] == -1 : # si il n'y a pas encore de classe
dmin = math.inf # la distance est la minimum
else :
dmin = distance(im[i,j], centres[classe[i][j]])
for m in range(nb_classe) :
dist = distance(list(im[i,j]), centres[m])
if dist<dmin :
dmin = dist
classe[i][j] = m
b = True
return(b)
# les centres bougent
def barycentre() :
global classe, im, nb_lignes, nb_colones, centres
dico = dict()
for i in range(nb_classe) :
dico[i] = []
for i in range(nb_lignes) :
for j in range(nb_colones) :
dico[classe[i][j]].append(im[i,j])
for i in range(nb_classe) :
r, g, b = 0, 0, 0
for e in dico[i] :
r += e[0]
g += e[1]
b += e[2]
m = len(dico[i])
centres[i] = [r//m, g//m, b//m]
# kmoyennes
i=0
while classer() :
i+=1
print("\nstep"+str(i))
print(centres)
barycentre()
im_classes = np.array([[centres[classe[i][j]] for j in range(nb_colones)] for i in range(nb_lignes)])
res = Image.fromarray(im_classes, mode='RGB')
# affichage,sauvegarde
colors = [[0,0,0],[150,0,0],[0,150,0],[0,0,150],[128,128,0],[0,160,160],[192,0,192],[230,230,230]] # liste des couleurs pour bien différencier les classes
# Enregistrer toutes les images
for lettre in range(nb_classe):
im_classes = np.array([[im[i][j] if classe[i][j] == lettre else (0, 0, 0) for j in range(nb_colones)] for i in range(nb_lignes)],dtype=np.uint8)
print(im_classes)
res = Image.fromarray(im_classes, mode="RGB")
res.show()
res.save(f"./out/2_{lettre}.jpg")
b = np.array([[colors[classe[i][j]] for j in range(nb_colones)] for i in range(nb_lignes)],dtype=np.uint8)
res = Image.fromarray( b,mode="RGB")
res.show()
res.save("./out/out.jpg")

651
Python Files/main.py Normal file
View File

@ -0,0 +1,651 @@
import numpy as np
import matplotlib.pyplot as plt
import imageio as io
from time import time
from random import choice
from math import pi, cos, sin, floor
from skimage.feature import peak_local_max
from os import system
import subprocess
from modules import *
# importation les fonctions permettant d'enregistrer des images
from images import *
## Variables globales
BLANC = 254 # définit le seuil pour la couleur blanche
MAX_INT = 42e42
## Liens des images sources
# Fonctions
## Fonction de base sur l'image
# Inverse l'image selon la coordonnée y
def inv_img_y(img: list) -> list:
return(img[::-1])
# lecture de l'image liée au lien [lien] depuis le serveur web
def read_img(lien: str) -> np.array:
im = io.v2.imread(lien)
im = np.array(im)
return(inv_img_y(im))
# affiche l'image [img].
# [cmap='gray'] premet d'afficher correctement les images en noir et blanc ainsi que les images en couleur
# pour les images en niveaux de gris, le pixel le plus sombre sera noir et le pixel le plus clair sera blanc.
# [rev] premet d'inverser l'image
def show_image(img: list, rev: bool = False) -> None:
plt.axis('off') # enlève les axes
if rev :
plt.imshow(img, cmap='gray',origin='lower', aspect='auto')
else :
plt.imshow(img, cmap='gray', aspect='auto')
## Traitement des images
# color_to_grayscale [image] convertis l'image [image] en RGB en une image (np.array) en niveau de gris
def color_to_grayscale(image: list) -> np.array:
image = list(image)
r = [[] for x in range(len(image))] #image vide
for i in range (len(image)) :
for j in range(len(image[i])) :
valeur = 0.2126*image[i][j][0] + 0.7152*image[i][j][1] + 0.0722*image[i][j][2] #formule de conversion de noir et blanc a couleur
r[i].append(valeur)
return np.array(r)
# grayscale_to_black_and_white img prend en entrée l'image [img] et renvoie un image en noir et blanc. les pixels
# de couleur superieure à [seuil] vont être laissé dans leur couleur originale et ceux inferieur a seuil vont etre mis en noir
# par default, la fonction conserve uniquement les pixels parfaitement blanc
def grayscale_to_black_and_white(img: np.array, seuil:int = BLANC) -> np.array:
r = [[] for x in range(len(img))]
for i in range(len(img)):
for j in range(len(img[i])):
if img[i][j] < seuil :
r[i].append(0)
else :
r[i].append(int(img[i][j]))
return(np.array(r))
## Matrice de Hough
# retourne la taille du tableau qui represente l'espace de hough.
# l'option precision change la taille du tableau selon la dimention x, c'est a dire selon les theta
def taille_Hough(img: list, precision: int = 1) -> tuple:
Px = len(img)
Py = len(img[0])
hauteur = (Px ** 2 + Py ** 2)**0.5 # distance maximum (coin en bas à gauche)
largeur = 360
return(round(hauteur), largeur*precision)
# rho_f(x, y, θ) retourne la distance a l'origine de la droite passant par le point (x, y) et d'angle θ
def rho_f(x: int, y: int, θ: float) -> float:
return(x*cos(θ) + y*sin(θ))
#retourne la matrice de l'espace Hough de l'image img dans l'ordre m[r][theta]
def espace_Hough(img: list, precision: int = 1) -> list:
hauteur_H, largeur_H = taille_Hough(img, precision)
hauteur_I, largeur_I = len(img), len(img[0])
#creer le tableau qui va contenir la matrice
matrice_hough = [[0 for i in range (largeur_H)] for i in range(hauteur_H)]
#on parcours toute l'image
for y in range(hauteur_I):
for x in range(largeur_I):
if img[y][x] >= BLANC:
for theta_deg in range(largeur_H):
theta_rad = theta_deg /(180 * precision) * pi
rho = round(rho_f(x, y, theta_rad))
if rho>0: #comme on fait varier θ jusqu'a 2π, on ne garde que les valeurs positives
matrice_hough[rho][theta_deg] += 1 #on met l'origine du repere en bas de l'image
return(matrice_hough)
# retourne une liste de maximum locaux.
def maximum_global(m: list, d: int = 100):
return(peak_local_max(np.array(m), min_distance=d))
## Géometrie
# calcule l'équation d'une droite passant par deux points en coordonnées carthésiennes.
# la valeur de retour sera un couple (a, b) représentant la droite sous forme y = ax + b
def equation(point1: tuple, point2: tuple) -> tuple:
(x1,y1),(x2,y2) = point1,point2
assert(x1 != x2), "les points sont alignés, la droite ne peut pas être prise en compte"
a = (y1 - y2) / (x1 - x2) #si la droite n'est pas verticale
b = y2 - a*x2
return(a,b)
# retourne les coefficients de l'equation de la droite représentée par une distance a l'origine r et un angle theta
# sous la forme d'un couple (a, b) représentant la droite sous forme y = ax + b
def droite(r: float, theta: float, precision: int = 1) -> tuple:
theta = theta / precision
if theta == 0 or theta == 180:
return (0,r)
else :
theta_rad = (pi/180)*theta
a = -(cos(theta_rad)/sin(theta_rad))
b = r/sin(theta_rad)
return(a,b)
# Renvoie la distance euclidienne entre les points a: (x1, y1) et b : (x2, y2)
def distance (a: tuple, b: tuple) -> int:
(x1,y1),(x2,y2) = a,b
distance = ( (x1-x2)**2 + (y1 - y2)**2 )**0.5
return(distance)
# calcule la matrice de Hough a l'aide de d'un programme en C qui utilise du multithreading.
# permet une vitesse d'execution beaucoup plus élevée : temps d'exécution divisé par 100
# l'argument bypass permet de tester d'autres partie du code plus rapidement
def hough_c(image: list, precision: int = 10, bypass: bool = False) -> list:
if not bypass:
save_img_c(image)
subprocess.run(['../c/multi.out', str(precision)])
mat = read_c()
return(mat)
# renvoit la matrice renvoyée par le calcul de l'espace de hough en C
def read_c() -> list:
f = open("../c/out.txt","r")
m_read = f.readlines()
f.close()
return([[int (x) for x in y.split(",")] for y in m_read])
# enregistre la liste [image] dans le dossier C sous le nom in.txt, pour pouvoir partager des informations entre C et python
def save_img_c(image: list) -> None:
f = open(f"../c/in.txt","w")
for i in image:
f.write(str(list(i)).replace(" ","").replace("[","").replace("]","") + "\n")
f.close()
#donne les intervalles de déb fin d'un segment de droite
def intervalle_une_droite(r: float, theta: float, plan: list, precision_h: int, blanc: int = BLANC) -> list:
(a,b) = droite(r, theta, precision_h)
largeur = len(plan) #axe des y
longueur = len(plan[0]) #axe des x
segments = []
x, deb, fin = 0, 0, 0
while x < longueur :
y = round(a*x + b)
if 0 < y < largeur :
if plan[y][x] >= blanc :
deb = x, y
while (0 < y < largeur) and x < longueur and (plan[y][x] >= blanc) :
x += 1
y = round(a*x +b)
fin = x, y
segments.append((deb, fin))
else :
x += 1
else :
x += 1
return(segments)
# Donne les intervalles (début,fin) d'une liste de droites
# in - listes_droites : couple (r, theta), plan: list
# out - [[(deb, fin) (...) (deb,fin)] [...] [(deb, fin) (...) (deb, fin)]
def intervalle(liste_droites: list, plan, precision_h:int) -> list:
n = len(liste_droites)
liste_intervalles =[]
for i in range (n):
r, theta = liste_droites[i][0], liste_droites[i][1]
segments = intervalle_une_droite(r, theta, plan, precision_h)
liste_intervalles.append(segments)
return(liste_intervalles)
# raccorde des segments qui sont peu éloignés (a une distance inferieur a distance_min) pour en faire une droite
def raccordement_un_intervalle(segments: list, distance_min:int) -> list:
new_segments = []
retry = False
i = 0
while i < len(segments) :
if (i < len(segments) -1 ) and (distance(segments[i][1], segments[i+1][0]) < distance_min) :
retry = True
new_segments.append((segments[i][0], segments[i+1][1]))
i += 1
else :
new_segments.append(segments[i])
i += 1
if retry :
return(raccordement_un_intervalle(new_segments, distance_min))
return(new_segments)
# raccorde des segments pour une liste d'intervalles d'une liste de droites
def raccordement(liste_segments: list, distance_min:int = 50) -> list:
new_segments = []
for i in liste_segments:
new_segments.append(raccordement_un_intervalle(i, distance_min=distance_min))
return(new_segments)
#enlève les intervalles trop petits, qui sont probablement des erreurs
def enlever_petits_intervalles_une_droite(segments: list, longueur_min: int) -> list:
new_segments =[]
for i in range (len(segments)):
if(distance(segments[i][0], segments[i][1])) > longueur_min:
new_segments.append(segments[i])
return(new_segments)
# applique la fonction enlever_petits_intervalles_une_droite sur chaque segement
def enlever_petits_intervalles_general(liste_segments: list, longueur_min:int = 150) -> list:
new_segments =[]
for i in liste_segments:
new_segments.append(enlever_petits_intervalles_une_droite(i, longueur_min))
return(new_segments)
# Retourne l'ensemble des points d'intersection entre deux segments
def intersection_deux_segments(segment1: tuple, segment2: tuple) -> tuple:
((xdeb1,ydeb1),(xfin1,yfin1)),((xdeb2,ydeb2),(xfin2,yfin2)) = segment1,segment2
(a1,b1), (a2,b2) = equation((xdeb1,ydeb1),(xfin1,yfin1)), equation((xdeb2,ydeb2),(xfin2,yfin2))
if a1 != a2:
x_sol = (b2 - b1) / (a1 - a2)
y_sol = a1 * x_sol + b1
if ((xdeb1 < x_sol < xfin1) or (xfin1 < x_sol < xdeb1)) and ((xdeb2 < x_sol < xfin2) or (xfin2 < x_sol < xdeb2)) and ((ydeb1 < y_sol < yfin1) or (yfin1 < y_sol < ydeb1)) and ((ydeb2 < y_sol < yfin2) or (yfin2 < y_sol < ydeb2)):
return (x_sol, y_sol)
# calcule toutes les intersections entre une liste de segments
# type : [[droite i] [...] [droite j] ] -> ((droite i, droite j), (x, y))
# avec (x,y) : les coordonnées du point d'intersection
def intersection_general(liste_segments):
n = len(liste_segments)
liste_intersection = []
for i in range (n):
for j in range (n):
if i > j: # permet d'eviter les doublons. La matrice est alors inferieur gauche.
try:
x,y = intersection_deux_segments(liste_segments[i],liste_segments[j])
liste_intersection.append(((liste_segments[i], liste_segments[j]), (x,y)))
except Exception as e:
# Il peut ne pas y avoir d'intersection entre ces deux segements, la fct intersection_deux_segments ne renvoie
# rien, on a donc une erreur et c'est pour cela qu'on passe.
pass
return (liste_intersection)
# transforme la une liste de liste en liste d'elements
def flatten(liste: list) -> list:
flat_list = []
for sublist in liste:
for item in sublist:
flat_list.append(item)
return(flat_list)
# calcule la matrice d'intersections
# renvoie : matrice[i][j] =(x,y) <=> (x,y) est le point d'intersection entre le ième et le jème segment de [liste_segments]
def matrice_intersections(liste_intersections: list, liste_segments: list):
len_segments = len(liste_segments) # nombres de routes
len_intersection = len(liste_intersections) # nombre d'intersections
m = [[ (-1,-1) for i in range(len_segments)] for j in range(len_segments)]
for z in range (len_intersection):
(droite_1,droite_2), (x,y) = liste_intersections[z]
index_i = liste_segments.index(droite_1)
index_j = liste_segments.index(droite_2)
m[index_i][index_j] = (x,y)
return(m)
# renvoie la matrice d'adjacence correspondant au graphe de notre ville
# on definit m[i][i] comme les coordonnées du point i et m[i][j] la distance entre le sommet i et le sommet j si ils sont relié. sinon, -1
# add_str permet de modifier le nom du fichier
def mat_adjacence(mat_intersections: list, liste_intersections: list, img_NB: list, img: list, add_str: str = ""):
liste_pts = list(set([x[1] for x in liste_intersections])) # enlève les doublons
n_r = len(liste_pts) # nb de routes
n_i = len(mat_intersections[0]) # nb de sommets
graphe_return = [[-1 for y in range(n_r)] for x in range(n_r)]
for i in range(n_r):
graphe_return[i][i] = liste_pts[i] # definition de m[i][i]
for j in range(n_r):
if i > j:
if voisin(liste_pts[i], liste_pts[j], img_NB):
d = int(distance(liste_pts[i], liste_pts[j]))
graphe_return[i][j] = d
graphe_return[j][i] = d
plt.plot((liste_pts[i][0], liste_pts[j][0]),(liste_pts[i][1], liste_pts[j][1]) )
return(graphe_return)
# renvoie si a et b sont des voisins.
# pour cela, on verifie si il y a plus de [p]% de points de route entre les deux
def voisin(pt1: tuple, pt2 : tuple, img : list, p: int = 60) -> tuple:
a, b = equation(pt1, pt2)
pts = [x for x in range(int(min(pt1[0], pt2[0])),int(max(pt1[0], pt2[0])))] # valeurs que doit prendre x sur le trajet
nb_tot = len(pts)
def f(x): # équation de la droite
return(int(a*x+b))
c = 0 # compteur de points blanc
for x in pts: # on compte le nombre de points blanc entre les deux points
if f(x) < len(img):
if img[f(x)][x] == BLANC :
c += 1
if nb_tot == 0 :
return(False)
return((c/(nb_tot)*100)>p)
# Applique l'algorithme de dijkstra à une matrice d'adjacence et un sommet de début donné
# Renvoie la liste des distances du sommet de départ à tout les autres
# la liste des sommets qui ont découvert t[i] (liste des parents)
def dijkstra(mat_adj: list, sommet_deb:int, sommet_fin: int):
vue = [sommet_deb] # liste des sommets déjà vu
n = len(mat_adj)
dist = [ -1 for i in range(n)] # liste des distances
dist[sommet_deb] = 0
liste_parents = [ -1 for i in range(n)]
nb = 0
for _ in range(n-1):
nb += 1
mini = MAX_INT # distance minimum des voisins
sommet_min = -1
a_decouvert = 0
for cur in range(n): # on parcours les sommets
if cur in vue : # si le sommet a déjà été vu
for vois in range(n): # on parcours ses voisins
if mat_adj[cur][vois] != -1 and not (vois in vue): # si il est de distance inferieure
if mat_adj[cur][vois] + dist[cur] < mini : # on le définit comme meilleur candidat et on continue
mini = mat_adj[cur][vois] + dist[cur]
sommet_min = vois
a_decouvert = cur
liste_parents[sommet_min] = a_decouvert # on conserve le meilleur candidat
dist[sommet_min] = mini
vue.append(sommet_min)
if sommet_min == sommet_fin:
break
return(liste_parents,dist, nb)
# Renvoie la liste des sommets à parcourir pour aller du sommet de début au sommet de fin à partir du tableau de dijkstra
# est appelé avec la liste des pères renvoyé par dijkstra
def chemin(liste_decouvre: list, sommet_fin:int) -> list:
liste_sommet = []
i = sommet_fin
while liste_decouvre[i] != -1 : # -1 est le sommet de départ
liste_sommet.append(i) # on est sensé ajouter les elements au début de la liste. On les ajoutes à la fin, puis on retourne la liste
i = liste_decouvre[i]
liste_sommet.append(i)
liste_sommet = liste_sommet[::-1]
return(liste_sommet)
# Renvoie la liste des sommets à parcourir à partir du graphe d'adj,
# le sommet de deb, repéré par son indice dans la matrice et le sommet de fin, repéré de même
def plus_court_chemin_dijkstra(mat_adj: list, sommet_deb:int, sommet_fin:int) -> list:
start_dijkstra = time()
liste_dec, _, nb_sommets = dijkstra(mat_adj, sommet_deb, sommet_fin)
pcc = chemin(liste_dec,sommet_fin)
return(pcc, nb_sommets, (time() - start_dijkstra))
# Algorithme A*
# [mat_adj] : matrice d'adjacence avec t[i][i] les coordonnées du point
# [h] heuristique : fonction d'estimation de la distance
# [s] sommet de depart
# [t] sommet d'arrivé
def a_etoile(mat_adj, h, s, t):
n = len(mat_adj[0]) # nb de sommets
f = FP()
f.push(s, 0)
liste_distance = [ MAX_INT for i in range(n)]
liste_distance[s] = 0
nb = 0
while not(f.is_empty()):
nb +=1
v = f.pop()
if v == t : # si on a atteint le sommet voulu
return(reconstruire(liste_distance, mat_adj, t), nb)
else : # sinon on s'applique sur chaque voisins
for u in voisins_a(v, mat_adj):
if liste_distance[u] > liste_distance[v] + mat_adj[v][u] :
liste_distance[u] = liste_distance[v] + mat_adj[v][u]
f.push(u, liste_distance[u] + h(mat_adj, u, t))
# voisins pour la fonction A*
# s est le sommet que l'on considère
def voisins_a(s: int, matrice_adj: list) -> list:
n = len(matrice_adj)
l = [] # liste des voisins
for i in range(n):
if i != s and matrice_adj[s][i] != -1: # si [i] et [s] sont voisin dans la matrice d'adjacence
l.append(i)
return(l)
# reconstuit le chemin de t a s, pour la fonction A*
# d est la liste des distances entre le sommet original et le sommet d[i]
# t est le sommet d'arrivée
def reconstruire(d: list, mat_adj: list, t: int) -> list:
r = d[t] # r est la distance restante avec le sommet de depart
chemin = [t] # on initialise le chemin avec le sommet d'arrivé
while r!=0 : # tant qu'il reste de la distance jusqu'au sommet de de depart
for u in range(len(mat_adj)): # on parcours tout les voisind de t
if u!=t : # -
if r == d[u] + mat_adj[u][t] : # si la distance restante est la distance entre le sommet u et le sommet de
chemin.append(u) # départ + la distance entre u et le sommet actuel
r = r - mat_adj[u][t] # on diminue la distance
t = u # on passe par ce sommet et on recommence l'algorithme
break
chemin.reverse()
return(chemin)
# Heuristique pour A*
# On utilise la distance à vol d'oiseau.
# C'est bien une heuristique acceptante.
def heuristique(mat_adj: list, sommet_act:int , sommet_fin:int) -> int:
x1,y1 = mat_adj[sommet_act][sommet_act]
x2,y2 = mat_adj[sommet_fin][sommet_fin]
dist_min = distance((x1,y1), (x2,y2))
return (dist_min)
# determine le nombre de points blanc d'une droite, en pouvant avancer de d points sans reset le compte
# droite est donnée sous la forme d'un couple (a, b)
# l'image dois être l'image en noir et blanc
# [d] est la distance maximale entre deux points blancs
def nombre_points_blanc(droite: tuple, img: list, d: int = MAX_INT) -> int:
n = len(img) # dimension de l'image
m = len(img[1]) # dimension de l'image
distance = d # distance max
liste_dist = [] # liste des suites de points blanc
(a,b) = droite
nmbre_points = 0 # nombre de points blanc
for x in range (m):
y = a*x+b
if (y<n) and (y>=0): # si on est bien dans l'image
if distance == 0 : # si on a trop avancé dans l'image sans croiser de points blancs
liste_dist.append(nmbre_points) #
nmbre_points = 0 # on reset le compte de points
distance = d # on reset la distance
if (img[int(y)][int(x)] >= BLANC): # si le pixel est blanc
nmbre_points+=1 # on incremente la valeur du nb de points
distance = d # on reset la distance
else :
distance -= 1 # on decremente la distance
liste_dist.append(nmbre_points)
return(max(liste_dist)) # valeur maximale d'une suite de points blanc
# fusionne les droites similaires
# liste est la liste des droites parametrée selon r et theta
# dico est un dictionnaire représentant les droites traitées et non traitées
# nb_lim est le nombre de pixel maximum de difference permettant la fusion de deux droites
# a_fact et b_fact sont les facteurs permettant de choisir les droites a prendres en comptes entre elles, en parametrage carthesien
def fusion_droites (liste: list, imageNB, dico: dict, a_fact: float, b_fact: float, nb_lim: int, precision_hough: int) -> list:
nouvelle_liste = []
modif = False
for i in range(len(liste)):
(r1,theta1) = liste[i]
for j in range(1, len(liste)):
(r2, theta2) = liste[j]
a1, b1 = droite(r1, theta1, precision_hough)
a2, b2 = droite(r2, theta2, precision_hough)
if r1 == r2 and theta1==theta2: # on ne se considere pas soit même
pass
else :
if (dico[(r1, theta1)]!=1) and (dico[(r2, theta2)]!=1): # on a déjà traiter la droite
min_a = min(abs(a1), abs(a2))
moy_a = abs(a1 + a2)/2
a_lim = a_fact + a_fact * min_a**2
if (abs(a1-a2) < a_lim): # si les droites sont suffisament proche selon les a
b_lim = b_fact + moy_a**2 * b_fact
if abs(b1 - b2) < b_lim : # si les droites sont suffisament proche selon des b
n1 = nombre_points_blanc((a1,b1), imageNB, 5)
n2 = nombre_points_blanc((a2,b2), imageNB, 5)
if (abs(n1-n2) < nb_lim): # on conserve la droite moyenne entre les deux
ntot = n1 + n2 # --
r_moy = (r1 + r2)/2 # --
theta_moy = (theta1 + theta2)/2 # --
nouvelle_liste.append((r_moy, theta_moy)) # --
elif ( n1 > n2 ): # on conserve uniquement la droite 1
nouvelle_liste.append((r1, theta1)) # --
else : # on conserve uniquement la droite 1
nouvelle_liste.append((r2, theta2)) # --
modif = True
dico[(r1, theta1)] = 1
dico[(r2, theta2)] = 1
if dico[(r1,theta1)]!=1:
nouvelle_liste.append((r1, theta1))
return(list(set(nouvelle_liste)), modif, dico)
# applique en boucle la fonction fusion_droites jusqu'à qu'il n'y ai plus de modifications
def fusion_droites_rec(liste: list, image: list , a_fact: int, b_fact: int, nb_lim: int, precision_hough: int) -> list:
dico = {} # Cas initial
for (r1,theta1) in liste:
dico[(r1,theta1)] = 0
nv_liste, booleen, dico = fusion_droites(liste, image, dico, a_fact, b_fact, nb_lim, precision_hough)
while booleen: # Le booleen représente si une modification a été faite ou non
dico = {} # si c'est le cas on recommence
for (r1,theta1) in nv_liste:
dico[(r1,theta1)] = 0
nv_liste, booleen, dico = fusion_droites(nv_liste, image, dico, a_fact, b_fact, nb_lim, precision_hough)
return(nv_liste)
# trie une liste selon la deuxieme coordonnée
def sort_list_theta(liste: list) -> list:
liste = [(x[1], x[0]) for x in liste]
liste.sort()
return([(x[1], x[0]) for x in liste])
# Permet de fusionner les intersections qui sont proches les une des autres, à partir de la matrice d'adjacence.
# distance_max est la distance à partir de laquelle on arrête de fusionner les droites.
def cluster(matrice_adj: list, distance_max: int) -> list:
for i in range(len(matrice_adj)): # on parcours l'intégralité des sommets
for j in range(i+1, len(matrice_adj)):
point1 = matrice_adj[i][i]
point2 = matrice_adj[j][j]
x1, y1 = point1
x2, y2 = point2
if distance(point1, point2) < distance_max and (x1,y1) != (-1, -1) and (x2,y2) != (-1, -1): # on supprime la valeur j et on introduit les anciennes valeurs dans i
matrice_adj[i][i] = (int((x1+x2)/2), int((y1+y2)/2)) # la coordonnée du point est la moyenne des deux
matrice_adj[j][j] = (-1, -1)
for k in range(len(matrice_adj)):
if k!=i and k != j:
if matrice_adj[j][k] != -1:
if matrice_adj[i][k] != -1:
matrice_adj[i][k] = (matrice_adj[i][k] + matrice_adj[j][k])/2
matrice_adj[k][i] = (matrice_adj[k][i] + matrice_adj[k][j])/2
else :
matrice_adj[i][k] = matrice_adj[j][k]
matrice_adj[k][i] = matrice_adj[k][j]
matrice_adj[j][k] = -1
matrice_adj[k][j] = -1
return(cluster(matrice_adj, distance_max))
return(matrice_adj)
def matrice_recadre(points, mat):
belle_matrice = [[0 for i in range(len(points))] for i in range(len(points))]
for i in range(len(points)):
for j in range(len(points)):
belle_matrice[i][j] = mat[points[i]][points[j]]
return(belle_matrice)
def main(lien: str, precision_hough:int = 1):
print("Lecture de l'image.") # uniquement a partir de plan
image = read_img(lien)
print("Conversion en niveau de gris.")
image_grayscale = color_to_grayscale(image)
print("Conversion en noir et blanc.")
image_NB = grayscale_to_black_and_white(image_grayscale)
print("Calcul de l'espace de Hough.")
espace_h = hough_c(image_NB, precision_hough)
save_hough(espace_h)
print("Récuperation des droites.")
liste_droites1 = peak_local_max(np.array(espace_h), min_distance=70, num_peaks=500, threshold_rel=0.23)
print(f"Nombre de droites : {len(liste_droites1)}.")
liste_droites1 = [list(x) for x in list(liste_droites1)]
save_with_droites(image, liste_droites1, precision_hough, "01. toutes les droites")
liste_droites2 = fusion_droites_rec(sort_list_theta(liste_droites1), image_NB, 0.5, 50, 10, precision_hough)
save_with_droites(image, liste_droites2, precision_hough, "02. premier filtrage des droites")
liste_droites3 = fusion_droites_rec(sort_list_theta(liste_droites2), image_NB, 0.3, 75, 10, precision_hough)
save_with_droites(image, liste_droites3, precision_hough, "03. deuxieme filtrage des droites")
print("Récupération de la listes des intervalles.")
liste_intervalles = intervalle(liste_droites3, image_NB, precision_hough)
save_liste_inter(liste_intervalles, image, "04. intervalles")
print("Raccorde les droites.")
liste_segments = raccordement(liste_intervalles, 28)
save_liste_inter(liste_segments, image, "05. raccordement (28)")
print("enlève les petits bouts de droite")
liste_segments = enlever_petits_intervalles_general(liste_segments)
save_liste_inter(liste_segments, image, "06. segments (28)")
liste_segments = flatten(liste_segments)
liste_intersections = intersection_general(liste_segments)
save_intersection(liste_intersections, image)
print("transformation en matrice d'intersections")
matrice_inter = matrice_intersections(liste_intersections, liste_segments)
matr_adj = mat_adjacence(matrice_inter, liste_intersections, image_NB, image)
print("clusterisation")
matrice_adj_cluster = cluster(matr_adj, 28)
save_cluster(matrice_adj_cluster, image)
save_graphe(matrice_adj_cluster, image)
#save_full_graphe(matrice_adj_cluster, image)
sommet_depart = 63
sommet_arrivee = 61
# d'autres valeurs intéressantes sont possibles : 61->73 ; 1->24
chemin_dijksra, nb_sommets_dijkstra, duree_dijksra = plus_court_chemin_dijkstra(matr_adj, sommet_depart, sommet_arrivee)
start_a_star = time()
chemin_a_star, nb_sommets_a_star = a_etoile(matr_adj, heuristique, sommet_depart, sommet_arrivee)
duree_a_star = (time() - start_a_star)
print(f"chemin dijkra : {chemin_dijksra}, temps d'execution : {duree_dijksra}, sommets parcourus : {nb_sommets_dijkstra}")
print(f"chemin A*: {chemin_a_star}, temps d'execution : {duree_a_star}, sommets parcourus : {nb_sommets_a_star}")
save_chemin(chemin_dijksra, matrice_adj_cluster, image, "dijkstra", "g")
save_chemin(chemin_a_star, matrice_adj_cluster, image, "a star", "k")
return(matrice_adj_cluster)
mat = main("https://server.ip/TIPE/paris2.png", 100)
#points = [25, 41, 3, 14, 52, 53, 54]
print(matrice_recadre([25, 41, 3, 14, 52, 53, 54], mat))

19
Python Files/modules.py Normal file
View File

@ -0,0 +1,19 @@
class FP:
def __init__(self):
self.tab_elem = [] # elements
self.tab_prio = [] # priorité
def push(self, sommet, prio): #ajoute l'élément sommet a la file de priorité
self.tab_elem.append(sommet)
self.tab_prio.append(prio)
def pop(self): # sort l'élément de priorité minimale
indice = self.tab_prio.index(min(self.tab_prio))
elem = self.tab_elem[indice]
self.tab_prio.pop(indice)
self.tab_elem.pop(indice)
return(elem)
def is_empty(self):
return(len(self.tab_prio) == 0)