# -*- coding: utf-8 -*-
"""
Ce module inclut une classe qui permet de
parcourir tous les segments de l'image.
:githublink:`%|py|7`
"""
import math
import copy
from .detection_segment_bord import SegmentBord_Commun
from .geometrie import Point
[docs]class SegmentBord(SegmentBord_Commun):
"""
Définit un segment allant d'un bord à un autre de l'image,
la classe va balayer toutes les orientations possibles,
pour chaque orientation, elle va ensuite balayer toute l'image,
* **angle** : orientation de balayage
* **fin** : pour le balayage de l'image à une orientation donnee,
le segment part d'un bord, fin désigne le dernier pixel
du contour à envisager avec cette orientation
* **vecteur** : vecteur directeur correspondant à angle
* **bord1** : numero du bord (0,1,2,3) correspondant à ``self.a``,
0 bord droit, 1 bord haut, 2 bord gauche, 3 bord bas
* **dangle** : orientation à visiter 0, dangle, 2*dangle, 3*dangle, ...
Pour parcourir les segments de l'image, on part d'un premier segment
(methode premier), segment horizontal, bord 0,
la méthode next passe au segment suivant jusqu'au dernier auquel
cas la methode retourne *False*.
Les segments sont orientés, si un gradient est proche du vecteur
normal, l'opposé ne l'est pas.
:githublink:`%|py|34`
"""
# voir la remarque de la classe Point a propos de __slots__
__slots__ = "angle", "fin", "vecteur", "bord1", "dangle"
[docs] def __init__(self, dim, dangle=math.pi / 24.0):
"""
initialise les dimensions et
fait sorte que la classe contienne le premier segment
:githublink:`%|py|41`
"""
SegmentBord_Commun.__init__(self, dim)
self.premier()
self.dangle = dangle
[docs] def __str__(self):
"""
permet d'afficher le segment
:githublink:`%|py|47`
"""
s = SegmentBord_Commun.__str__(self)
s += " -- bord " + str(self.bord1)
s += " -- fin " + str(self.fin)
s += " -- a " + "%3.1f" % (self.angle * 180 / math.pi)
s += " -- vec " + "%2.2f,%2.2f" % (self.vecteur.x, self.vecteur.y)
return s
[docs] def premier(self):
"""
définit le premier segment, horizontal, part du bord gauche
:githublink:`%|py|56`
"""
self.angle = 0
self.fin = Point(0, 0)
self.calcul_vecteur()
[docs] def milieu(self):
"""
Un autre segment, pour débugger le programme,
choisit une orientation pour laquelle on sait que le
résultat doit être un segment significatif,
la methode *next* ira plus vite au dernier segment.
:githublink:`%|py|67`
"""
self.angle = math.pi / 2
self.calcul_vecteur()
[docs] def calcul_vecteur(self):
"""
En fonction de l'angle, calcule le vecteur direction du segment,
ensuite fixe la première extrémité du segment ``self.a``
et détermine la dernière des premières extremités pour
un segment de cette orientation (angle).
:githublink:`%|py|77`
"""
self.vecteur = Point(math.cos(self.angle), math.sin(self.angle))
# le vecteur est horizontal
if abs(self.vecteur.x) < 1e-5:
if self.vecteur.y > 0:
# vers le haut, un seul bord pour la premiere extremite
self.bord1 = 3
self.a.x = 0
self.a.y = 0
self.fin.x = self.dim.x - 1
self.fin.y = 0
return self.calcul_vecteur_fin()
else:
# vers le bas, un seul bord pour la premiere extremite
self.bord1 = 1
self.a.x = self.dim.x - 1
self.a.y = self.dim.y - 1
self.fin.x = 0
self.fin.y = self.dim.y - 1
return self.calcul_vecteur_fin()
# le vecteur est vertical
if abs(self.vecteur.y) < 1e-5:
if self.vecteur.x < 0:
# vers la droite, un seul bord pour la premiere extremite
self.bord1 = 0
self.a.x = self.dim.x - 1
self.a.y = 0
self.fin.x = self.dim.x - 1
self.fin.y = self.dim.y - 1
return self.calcul_vecteur_fin()
else:
# vers la gauche, un seul bord pour la premiere extremite
self.bord1 = 2
self.a.x = 0
self.a.y = self.dim.y - 1
self.fin.x = 0
self.fin.y = 0
return self.calcul_vecteur_fin()
if self.vecteur.x < 0:
if self.vecteur.y < 0:
# en bas a gauche, deux bords pour la premiere extremite
self.bord1 = 0
self.a.x = self.dim.x - 1
self.a.y = 0
self.fin.x = 0
self.fin.y = self.dim.y - 1
return self.calcul_vecteur_fin()
else:
# en haut a gauche, deux bords pour la premiere extremite
self.bord1 = 3
self.a.x = 0
self.a.y = 0
self.fin.x = self.dim.x - 1
self.fin.y = self.dim.y - 1
return self.calcul_vecteur_fin()
else:
if self.vecteur.y < 0:
# en haut a droite, deux bords pour la premiere extremite
self.bord1 = 1
self.a.x = self.dim.x - 1
self.a.y = self.dim.y - 1
self.fin.x = 0
self.fin.y = 0
return self.calcul_vecteur_fin()
else:
# en bas a droite, deux bords pour la premiere extremite
self.bord1 = 2
self.a.x = 0
self.a.y = self.dim.y - 1
self.fin.x = self.dim.x - 1
self.fin.y = 0
return self.calcul_vecteur_fin()
[docs] def calcul_vecteur_fin(self):
"""
propose une seconde extrémité connaissant la première,
beaucoup plus loin en conservant la meme orientation,
du moment qu'on traverse l'image
:githublink:`%|py|156`
"""
t = self.dim.x + self.dim.y
self.b.x = int(self.a.x + self.vecteur.x * t)
self.b.y = int(self.a.y + self.vecteur.y * t)
[docs] def directeur(self):
"""
retourne une copie du vecteur directeur
:githublink:`%|py|162`
"""
return copy.copy(self.vecteur)
[docs] def next(self):
"""
passe au segment suivant dans le parcours de l'image
:githublink:`%|py|166`
"""
if self.angle >= math.pi * 2 - 1e-5:
# toute orientation visitee
return False
if self.a == self.fin:
# tout vecteur visitee pour la meme orientation,
# on passe a l'orientation suivante
self.angle += self.dangle
self.calcul_vecteur()
if self.angle >= math.pi * 2:
return False
else:
return True
else:
# on passe au segment suivant selon la meme orientation,
# tout depend du bord sur lequel on est
if self.bord1 == 0:
# bord droit
if self.a.y < self.dim.y - 1:
# pas besoin de changer de bord
self.a.y += 1
else:
# on passe au bord suivant, bord haut
self.bord1 = 1
self.a.x -= 1
elif self.bord1 == 1:
# bord haut, meme raisonnement que pour le premier bord
if self.a.x > 0:
self.a.x -= 1
else:
self.bord1 = 2
self.a.y -= 1
elif self.bord1 == 2:
# bord gauche, meme raisonnement que pour le premier bord
if self.a.y > 0:
self.a.y -= 1
else:
self.bord1 = 3
self.a.x += 1
elif self.bord1 == 3:
# bord bas, meme raisonnement que pour le premier bord
if self.a.x < self.dim.x - 1:
self.a.x += 1
else:
self.bord1 = 0
self.a.y += 1
# choisit une derniere extremite
self.calcul_vecteur_fin()
return True
[docs] def calcul_bord2(self):
"""
calcule précisément la second extrémité, parcourt la demi-droite
jusqu'à sortir de l'image, le dernier point est la seconde extrémité
:githublink:`%|py|220`
"""
a = self.a.arrondi()
p = copy.copy(self.a)
n = self.directeur()
i = 0
while a.x >= 0 and a.y >= 0 and a.x < self.dim.x and a.y < self.dim.y:
p += n
a = p.arrondi()
i += 1
self.b.x = a.x
self.b.y = a.y
r = -1
if self.b.x < 0:
self.b.x = 0
r = 2
if self.b.x >= self.dim.x:
self.b.x = self.dim.x - 1
r = 0
if self.b.y < 0:
self.b.y = 0
r = 3
if self.b.y >= self.dim.y:
self.b.y = self.dim.y - 1
r = 1
return r