main.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. ### Modules ###
  2. from PIL import Image, ImageFilter
  3. from numpy import asarray, ndarray, array, uint8, delete
  4. from random import choices, randint, random
  5. from copy import deepcopy
  6. import drawsvg as dw
  7. ### Fonctions ###
  8. def import_image(chemin: str, resize: bool = False, lap: bool = False) -> ndarray :
  9. """Charge l'image donnée, la passe en nuances de gris, et la convertit en tableau (de numpy)"""
  10. ## Chargement de l'image ##
  11. # On essaie d'ouvrir l'image avec la librairie PIL
  12. try:
  13. image = Image.open(chemin)
  14. # Gestion d'erreur si le fichier n'est pas accessible ou n'existe pas
  15. except FileNotFoundError:
  16. print("Le chemin d'accès est invalide.")
  17. # TODO Set image sur une image blanche en cas d'erreur
  18. # Gestion d'erreur dans les autres cas
  19. except:
  20. print("Une erreur s'est produite")
  21. # TODO Pareil qu'au dessus
  22. ## Conversion de l'image en nuances de gris ##
  23. # On utilise la méthode .convert() de PIL
  24. image = image.convert("L")
  25. if resize:
  26. image = image.resize((400, 400))
  27. if lap:
  28. image = image.filter(ImageFilter.FIND_EDGES)
  29. ## Conversion en tableau ##
  30. # On utilise la fonction asarrray() de numpy
  31. image_array = asarray(image)
  32. return image_array
  33. def tab_image_blanche(longueur: int, hauteur: int) -> ndarray:
  34. """Génère un tableau contenant des pixels blancs avec les dimensions données"""
  35. # On crée autant de lignes que de pixels de hauteur, et autant de pixels que de hauteur
  36. tab = [ [255] * longueur] * hauteur
  37. return array(tab)
  38. def tab_image_noire(longueur: int, hauteur: int) -> ndarray:
  39. """Génère un tableau contenant des pixels noirs avec les dimensions données"""
  40. # On crée autant de lignes que de pixels de hauteur, et autant de pixels que de hauteur
  41. tab = [ [0] * longueur] * hauteur
  42. return array(tab)
  43. def tab_image_grise(longueur: int, hauteur: int) -> ndarray:
  44. """Génère un tableau contenant des pixels gris avec les dimensions données"""
  45. # On crée autant de lignes que de pixels de hauteur, et autant de pixels que de hauteur
  46. tab = [ [127] * longueur] * hauteur
  47. return array(tab)
  48. def get_longueur_img(tab_img: ndarray) -> int:
  49. """Renvoie la longueur du tableau à deux dimensions (représentant une image) donné"""
  50. return len(tab_img[0])
  51. def get_hauteur_img(tab_img: ndarray) -> int:
  52. """Renvoie la hauteur du tableau à deux dimensions (représentant une image) donné"""
  53. return len(tab_img)
  54. def assombrir_pixel(tab_img: ndarray, ligne: int, colonne: int) -> ndarray:
  55. """Réduit de 51 (parce que c'est 255/5) les valeurs des couleurs du pixel à la position donnée."""
  56. if tab_img[ligne][colonne] >= 51:
  57. tab_img[ligne][colonne] = tab_img[ligne][colonne] - 51
  58. return tab_img
  59. def eclaircir_pixel(tab_img: ndarray, ligne: int, colonne: int) -> ndarray:
  60. """Augmente de 51 (parce que c'est 255/5) les valeurs des couleurs du pixel à la position donnée."""
  61. if tab_img[ligne][colonne] <= 214:
  62. tab_img[ligne][colonne] += 51
  63. return tab_img
  64. def generer_clous(tab_img: ndarray) -> list:
  65. """Génère un tableau qui contient des tuples qui représentent des clous : deux coordonnées et un numéro de côté -> 0 pour le haut, 1 pour la droite, 2 pour le bas, 3 pour la gauche"""
  66. liste_res = []
  67. h = get_hauteur_img(tab_img)
  68. l = get_longueur_img(tab_img)
  69. for i in range(0, l, 10):
  70. liste_res = liste_res + [(i, 0, 0)]
  71. for i in range(10, h, 10):
  72. liste_res = liste_res + [(l - 1, i, 1)]
  73. for i in range(l - 11, -1, - 10):
  74. liste_res = liste_res + [(i, h - 1, 2)]
  75. for i in range(h - 11, 0, -10):
  76. liste_res = liste_res + [(0, i, 3)]
  77. return liste_res
  78. def generer_clous_plus_clous_aleatoires(tab_img):
  79. """Génère un tableau de clous classiques (cf generer_clous) + des clous aleatoires au milieu de l'image"""
  80. h = get_hauteur_img(tab_img)
  81. l = get_longueur_img(tab_img)
  82. liste_res = generer_clous(tab_img)
  83. for i in range(0, 400):
  84. liste_res.append((randint(20, l - 20), randint(20, h - 20), i + 4))
  85. return liste_res
  86. def visible(clou1: tuple, clou2: tuple) -> bool:
  87. """Renvoie True si les clous se voient, False sinon"""
  88. return clou1[2] != clou2[2]
  89. def tracer_droite(clou1: tuple, clou2: tuple, image: ndarray) -> ndarray:
  90. """Trace une droite noire d'un clou à un autre."""
  91. if visible(clou1, clou2):
  92. liste_points = liste_points_traverses(clou1[0], clou1[1], clou2[0], clou2[1])
  93. for i in range(0, len(liste_points)):
  94. ligne = liste_points[i][1]
  95. col = liste_points[i][0]
  96. image = assombrir_pixel(image, ligne, col)
  97. return image
  98. def tracer_droite_blanche(clou1: tuple, clou2: tuple, image: ndarray) -> ndarray:
  99. """Trace une droite blanche d'un clou à un autre."""
  100. if visible(clou1, clou2):
  101. liste_points = liste_points_traverses(clou1[0], clou1[1], clou2[0], clou2[1])
  102. for i in range(0, len(liste_points)):
  103. ligne = liste_points[i][1]
  104. col = liste_points[i][0]
  105. image = eclaircir_pixel(image, ligne, col)
  106. return image
  107. def liste_points_traverses(x1: int, y1: int, x2: int, y2: int) -> list:
  108. """Renvoie les points que le segment [(x1, y1), (x2, y2)] traverse"""
  109. liste_res = []
  110. a, b = calcul_droite(x1, y1, x2, y2)
  111. # Si l'angle entre l'axe des abscisses et la droite est compris entre -45° et 45°
  112. if -1 <= a <= 1:
  113. if x1 > x2:
  114. # On cherche y pour chaque x, donc on commence du point dont le x est le plus proche de 0
  115. x1, y1, x2, y2 = x2, y2, x1, y1
  116. x = x1 + 1
  117. y = y1
  118. liste_res.append((x1, y))
  119. while x <= x2:
  120. y = round(a * x + b)
  121. liste_res.append((x, y))
  122. x += 1
  123. else:
  124. if y1 > y2:
  125. # On cherche x pour chaque y, donc on commence du point dont le y est le plus proche de 0
  126. x1, y1, x2, y2 = x2, y2, x1, y1
  127. if a != 999999999 and b != 999999999:
  128. x = x1
  129. y = y1 + 1
  130. liste_res.append((x, y1))
  131. while y <= y2:
  132. x = round((y - b) / a)
  133. liste_res.append((x, y))
  134. y += 1
  135. # Gestion des droites verticales
  136. else:
  137. x = x1
  138. y = y1 + 1
  139. liste_res.append((x, y1))
  140. for i in range(y, y2 + 1):
  141. liste_res.append((x, i))
  142. return liste_res
  143. def calcul_droite(x1: int, y1: int, x2: int, y2: int) -> tuple:
  144. """Renvoie le coefficient directeur et l'ordonnée à l'origine de la droite passant par (x1, y1) et (x2, y2)"""
  145. if x1 != x2:
  146. a = (y2 - y1) / (x2 - x1)
  147. b = y1 - x1 * a
  148. # Gestion des droites verticales
  149. else:
  150. a = 999999999
  151. b = 999999999
  152. return (a, b)
  153. def liste_clous_al(liste_clous : list, taille_l : int) -> list:
  154. """On créer une liste de clou choisis aléatoirement"""
  155. lst_res = choices(liste_clous, k=taille_l)
  156. return lst_res
  157. def reduction_erreur_droite(clou_dep: tuple, clou_arr: tuple, img1: ndarray, img2: ndarray) -> float:
  158. """Renvoie la différence entre l'erreur de l'image cible et de l'image actuelle, et l'erreur de l'image cible et de l'image actuelel si on traçait la droite noire donnée"""
  159. if not visible(clou_dep, clou_arr):
  160. return 999999999
  161. lst_pts = liste_points_traverses(clou_dep[0], clou_dep[1], clou_arr[0], clou_arr[1])
  162. err_act = 0
  163. nb_pts = len(lst_pts)
  164. for i in range(0, nb_pts):
  165. err_act += erreur_point(lst_pts[i], img1, img2)
  166. new_err = 0
  167. for i in range(0, nb_pts):
  168. new_err += erreur_point_assombri(lst_pts[i], img1, img2)
  169. return (new_err - err_act) / nb_pts
  170. def reduction_erreur_droite_blanche(clou_dep: tuple, clou_arr: tuple, img1: ndarray, img2: ndarray) -> float:
  171. """Renvoie la différence entre l'erreur de l'image cible et de l'image actuelle, et l'erreur de l'image cible et de l'image actuelel si on traçait la droite blanche donnée"""
  172. if not visible(clou_dep, clou_arr):
  173. return 999999999
  174. lst_pts = liste_points_traverses(clou_dep[0], clou_dep[1], clou_arr[0], clou_arr[1])
  175. err_act = 0
  176. nb_pts = len(lst_pts)
  177. for i in range(0, nb_pts):
  178. err_act += erreur_point(lst_pts[i], img1, img2)
  179. new_err = 0
  180. for i in range(0, nb_pts):
  181. new_err += erreur_point_eclairci(lst_pts[i], img1, img2)
  182. return (new_err - err_act) / nb_pts
  183. def erreur_point(p: tuple, img1: ndarray, img2: ndarray):
  184. """Renvoie la différence entre la valeur du pixel sur l'image 1 et la valeur du pixel sur l'image 2"""
  185. return abs(img1[p[1]][p[0]] - img2[p[1]][p[0]])
  186. def erreur_point_assombri(p: tuple, img1: ndarray, img2: ndarray):
  187. """Renvoie la différence entre la valeur du pixel sur l'image 1 et la valeur du pixel sur l'image 2 lorsqu'on assombrit ce pixel"""
  188. if img2[p[1]][p[0]] >= 51:
  189. return abs(img1[p[1]][p[0]] - img2[p[1]][p[0]] + 51)
  190. else:
  191. return erreur_point(p, img1, img2)
  192. def erreur_point_eclairci(p: tuple, img1: ndarray, img2: ndarray):
  193. """Renvoie la différence entre la valeur du pixel sur l'image 1 et la valeur du pixel sur l'image 2 lorsqu'on éclaircit ce pixel"""
  194. if img2[p[1]][p[0]] <= 51:
  195. return abs(img1[p[1]][p[0]] - img2[p[1]][p[0]] - 51)
  196. else:
  197. return erreur_point(p, img1, img2)
  198. def trouve_meilleure_droite(img1: ndarray, img2: ndarray, clou_dep: tuple, lst_clous: list) -> tuple:
  199. """Renvoie le clou dont la droite le traversant lui et le clou de départ réduit le plus l'erreur entre les deux images"""
  200. liste_c = liste_clous_al(lst_clous, len(lst_clous) // 2)
  201. liste_red_err = []
  202. for i in range(0, len(liste_c)):
  203. liste_red_err.append(reduction_erreur_droite(clou_dep, liste_c[i], img1, img2))
  204. red_err = min(liste_red_err)
  205. meilleur_clou = liste_c[liste_red_err.index(red_err)]
  206. return (meilleur_clou, red_err)
  207. def trouve_meilleure_droite_blanche(img1: ndarray, img2: ndarray, clou_dep: tuple, lst_clous: list) -> tuple:
  208. """Renvoie le clou dont la droite blanche le traversant lui et le clou de départ réduit le plus l'erreur entre les deux images"""
  209. liste_c = liste_clous_al(lst_clous, len(lst_clous) // 2)
  210. liste_red_err = []
  211. for i in range(0, len(liste_c)):
  212. liste_red_err.append(reduction_erreur_droite_blanche(clou_dep, liste_c[i], img1, img2))
  213. red_err = min(liste_red_err)
  214. meilleur_clou = liste_c[liste_red_err.index(red_err)]
  215. return (meilleur_clou, red_err)
  216. def generer_clous_lap(tab_img: ndarray) -> list:
  217. """Génère un tableau qui contient des tuples qui représentent des clous : deux coordonnées et un numéro de côté -> 0 pour le haut, 1 pour la droite, 2 pour le bas, 3 pour la gauche"""
  218. liste_res = []
  219. # On crée la matrice qui contient pour chaque pixel, la somme de sa valeur et de celle de tous les pixels d'avant
  220. tab_somme = somme_cumulative_matrice(tab_img)
  221. # Le dernier élément est la somme de la valeur de tous les pixels
  222. somme_valeurs_px = tab_somme[-1][-1]
  223. for i in range(600):
  224. nb_rd = random() * somme_valeurs_px
  225. pixel = trouve_pixel(tab_somme, nb_rd)
  226. clou = (pixel[1], pixel[0], i)
  227. liste_res.append(clou)
  228. return liste_res
  229. def somme_cumulative_matrice(tab: ndarray) -> list:
  230. """Renvoie la somme cumulative de la matrice"""
  231. liste_res = []
  232. for i in range(len(tab)):
  233. liste_res.append([])
  234. for j in range(len(tab[i])):
  235. if j == 0:
  236. if i == 0:
  237. liste_res[i].append(int(tab[i][j]) ** 2)
  238. else:
  239. liste_res[i].append(int(tab[i][j]) ** 2 + liste_res[i - 1][-1])
  240. else:
  241. liste_res[i].append(int(tab[i][j]) ** 2 + liste_res[i][j - 1])
  242. return liste_res
  243. def trouve_pixel(tab: list, nb: float) -> tuple:
  244. """Renvoie les coordonnées du premier nombre dans la matrice qui est plus grand que le nombre donné"""
  245. for i in range(len(tab)):
  246. for j in range(len(tab[i])):
  247. if tab[i][j] >= nb:
  248. return (i, j)
  249. ## Fonctions de retraçage ##
  250. def retrace_image(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  251. """Retrace l'image donnée avec des fils et sauvegarde dans le dossier resultat, au chemin donné"""
  252. image = import_image(chemin_img_source, resize)
  253. new_img = tab_image_blanche(get_longueur_img(image), get_hauteur_img(image))
  254. clous = generer_clous(new_img)
  255. clou_dep = clous[0]
  256. cpt_augmentation_err = 0
  257. cpt_droites = 0
  258. while cpt_augmentation_err < 3:
  259. meilleur_clou, reduction_err = trouve_meilleure_droite(image, new_img, clou_dep, clous)
  260. print(reduction_err, clou_dep, meilleur_clou)
  261. if reduction_err >= 0:
  262. cpt_augmentation_err += 1
  263. # On ne trace la droite que si elle réduit l'erreur
  264. else:
  265. cpt_augmentation_err = 0
  266. new_img = tracer_droite(clou_dep, meilleur_clou, new_img)
  267. clou_dep = meilleur_clou
  268. cpt_droites += 1
  269. print(cpt_droites)
  270. image_res = Image.fromarray(uint8(new_img))
  271. image_res.save("resultat/" + nom_image_sortie + ".png")
  272. def retrace_image_deux_fils(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  273. """Retrace l'image donnée avec un fil noir et un fil blanc sur un fond gris et sauvegarde dans le dossier resultatnb, au chemin donné"""
  274. image = import_image(chemin_img_source, resize)
  275. new_img = tab_image_grise(get_longueur_img(image), get_hauteur_img(image))
  276. clous = generer_clous(new_img)
  277. clou_dep_noir = clous[0]
  278. clou_dep_blanc = clous[0]
  279. cpt_augmentation_err = 0
  280. cpt_droites = 0
  281. while cpt_augmentation_err < 5:
  282. meilleur_clou_noir, reduction_err_noire = trouve_meilleure_droite(image, new_img, clou_dep_noir, clous)
  283. meilleur_clou_blanc, reduction_err_blanche = trouve_meilleure_droite_blanche(image, new_img, clou_dep_blanc, clous)
  284. if reduction_err_noire <= reduction_err_blanche:
  285. print(reduction_err_noire, clou_dep_noir, meilleur_clou_noir)
  286. if reduction_err_noire >= 0:
  287. cpt_augmentation_err += 1
  288. # On ne trace la droite que si elle réduit l'erreur
  289. else:
  290. cpt_augmentation_err = 0
  291. new_img = tracer_droite(clou_dep_noir, meilleur_clou_noir, new_img)
  292. clou_dep_noir = meilleur_clou_noir
  293. cpt_droites += 1
  294. else:
  295. print(reduction_err_blanche, clou_dep_blanc, meilleur_clou_blanc)
  296. if reduction_err_blanche >= 0:
  297. cpt_augmentation_err += 1
  298. # On ne trace la droite que si elle réduit l'erreur
  299. else:
  300. cpt_augmentation_err = 0
  301. new_img = tracer_droite_blanche(clou_dep_blanc, meilleur_clou_blanc, new_img)
  302. clou_dep_blanc = meilleur_clou_blanc
  303. cpt_droites += 1
  304. print(cpt_droites)
  305. image_res = Image.fromarray(uint8(new_img))
  306. image_res.save("resultatnb/" + nom_image_sortie + ".png")
  307. def retrace_image_clous_aleatoires(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  308. """Retrace l'image donnée avec des fils et sauvegarde dans le dossier resultat, au chemin donné"""
  309. image = import_image(chemin_img_source, resize)
  310. new_img = tab_image_blanche(get_longueur_img(image), get_hauteur_img(image))
  311. svg = dw.Drawing(get_longueur_img(image), get_hauteur_img(image))
  312. svg.append(dw.Rectangle(x=0, y=0, width='100%', height='100%', fill='white'))
  313. clous = generer_clous_plus_clous_aleatoires(new_img)
  314. clou_dep = clous[0]
  315. cpt_augmentation_err = 0
  316. cpt_droites = 0
  317. while cpt_augmentation_err < 3:
  318. meilleur_clou, reduction_err = trouve_meilleure_droite(image, new_img, clou_dep, clous)
  319. print(reduction_err, clou_dep, meilleur_clou)
  320. if reduction_err >= 0:
  321. cpt_augmentation_err += 1
  322. # On ne trace la droite que si elle réduit l'erreur
  323. else:
  324. cpt_augmentation_err = 0
  325. new_img = tracer_droite(clou_dep, meilleur_clou, new_img)
  326. svg.append(dw.Line(clou_dep[0], clou_dep[1], meilleur_clou[0], meilleur_clou[1], stroke='black', stroke_opacity=0.2, stroke_width=1))
  327. clou_dep = meilleur_clou
  328. cpt_droites += 1
  329. print(cpt_droites)
  330. image_res = Image.fromarray(uint8(new_img))
  331. image_res.save("resultat-clous-al/" + nom_image_sortie + ".png")
  332. svg.save_svg("resultat-clous-al/" + nom_image_sortie + ".svg")
  333. def retrace_image_clous_aleatoires_b_sur_n(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  334. """Retrace l'image donnée avec des fils blancs sur fond noir et sauvegarde dans le dossier resultat, au chemin donné"""
  335. image = import_image(chemin_img_source, resize)
  336. new_img = tab_image_noire(get_longueur_img(image), get_hauteur_img(image))
  337. clous = generer_clous_plus_clous_aleatoires(new_img)
  338. clou_dep = clous[0]
  339. cpt_augmentation_err = 0
  340. cpt_droites = 0
  341. while cpt_augmentation_err < 3:
  342. meilleur_clou, reduction_err = trouve_meilleure_droite_blanche(image, new_img, clou_dep, clous)
  343. print(reduction_err, clou_dep, meilleur_clou)
  344. if reduction_err >= 0:
  345. cpt_augmentation_err += 1
  346. # On ne trace la droite que si elle réduit l'erreur
  347. else:
  348. cpt_augmentation_err = 0
  349. new_img = tracer_droite_blanche(clou_dep, meilleur_clou, new_img)
  350. clou_dep = meilleur_clou
  351. cpt_droites += 1
  352. print(cpt_droites)
  353. image_res = Image.fromarray(uint8(new_img))
  354. image_res.save("resultat-clous-al-bsn/" + nom_image_sortie + ".png")
  355. ### Laplacien ###
  356. def retrace_avec_laplacien(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  357. """Retrace l'image donnée avec des fils en s'aidant d'un filtre laplacien et sauvegarde dans le dossier resultat, au chemin donné"""
  358. image = import_image(chemin_img_source, resize)
  359. new_img = tab_image_blanche(get_longueur_img(image), get_hauteur_img(image))
  360. svg = dw.Drawing(get_longueur_img(image), get_hauteur_img(image))
  361. svg.append(dw.Rectangle(x=0, y=0, width='100%', height='100%', fill='white'))
  362. image_lap = import_image(chemin_img_source, resize, lap=True) # On importe l'image en laplacien grâce à lap=True
  363. clous = generer_clous_lap(image_lap)
  364. clou_dep = clous[0]
  365. cpt_augmentation_err = 0
  366. cpt_droites = 0
  367. while cpt_augmentation_err < 3:
  368. meilleur_clou, reduction_err = trouve_meilleure_droite(image, new_img, clou_dep, clous)
  369. print(reduction_err, clou_dep, meilleur_clou)
  370. if reduction_err >= 0:
  371. cpt_augmentation_err += 1
  372. # On ne trace la droite que si elle réduit l'erreur
  373. else:
  374. cpt_augmentation_err = 0
  375. new_img = tracer_droite(clou_dep, meilleur_clou, new_img)
  376. svg.append(dw.Line(clou_dep[0], clou_dep[1], meilleur_clou[0], meilleur_clou[1], stroke='black', stroke_opacity=0.2, stroke_width=1))
  377. # Image.fromarray(uint8(new_img)).save("gif-pommes/" + str(cpt_droites).zfill(5) + ".png")
  378. clou_dep = meilleur_clou
  379. cpt_droites += 1
  380. print(cpt_droites)
  381. image_res = Image.fromarray(uint8(new_img))
  382. image_res.save("resultat-laplacien/" + nom_image_sortie + ".png")
  383. svg.save_svg("resultat-laplacien/" + nom_image_sortie + ".svg")
  384. def retrace_avec_laplacien_traits_blancs(chemin_img_source: str, nom_image_sortie: str, resize: bool = False):
  385. """Retrace l'image donnée avec des fils blancs en s'aidant d'un filtre laplacien et sauvegarde dans le dossier resultat, au chemin donné"""
  386. image = import_image(chemin_img_source, resize)
  387. new_img = tab_image_noire(get_longueur_img(image), get_hauteur_img(image))
  388. svg = dw.Drawing(get_longueur_img(image), get_hauteur_img(image))
  389. svg.append(dw.Rectangle(x=0, y=0, width='100%', height='100%', fill='black'))
  390. image_lap = import_image(chemin_img_source, resize, lap=True) # On importe l'image en laplacien grâce à lap=True
  391. clous = generer_clous_lap(image_lap)
  392. clou_dep = clous[0]
  393. cpt_augmentation_err = 0
  394. cpt_droites = 0
  395. while cpt_augmentation_err < 3:
  396. meilleur_clou, reduction_err = trouve_meilleure_droite_blanche(image, new_img, clou_dep, clous)
  397. print(reduction_err, clou_dep, meilleur_clou)
  398. if reduction_err >= 0:
  399. cpt_augmentation_err += 1
  400. # On ne trace la droite que si elle réduit l'erreur
  401. else:
  402. cpt_augmentation_err = 0
  403. new_img = tracer_droite_blanche(clou_dep, meilleur_clou, new_img)
  404. svg.append(dw.Line(clou_dep[0], clou_dep[1], meilleur_clou[0], meilleur_clou[1], stroke='white', stroke_opacity=0.2, stroke_width=1))
  405. # Image.fromarray(uint8(new_img)).save("gif-pommes/" + str(cpt_droites).zfill(5) + ".png")
  406. clou_dep = meilleur_clou
  407. cpt_droites += 1
  408. print(cpt_droites)
  409. image_res = Image.fromarray(uint8(new_img))
  410. image_res.save("resultat-laplacien-bsn/" + nom_image_sortie + ".png")
  411. svg.save_svg("resultat-laplacien-bsn/" + nom_image_sortie + ".svg")
  412. ### Tests ###
  413. retrace_avec_laplacien_traits_blancs("images/hibou.jpg", "hibou-400px-600clous", True)