Coverage for src/mlstatpy/image/detection_segment/detection_segment_segangle.py: 94%
144 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-27 05:59 +0100
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-27 05:59 +0100
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Ce module inclut une classe qui permet de
5parcourir tous les segments de l'image.
6"""
7import math
8import copy
9from .detection_segment_bord import SegmentBord_Commun
10from .geometrie import Point
13class SegmentBord(SegmentBord_Commun):
14 """
15 Définit un segment allant d'un bord à un autre de l'image,
16 la classe va balayer toutes les orientations possibles,
17 pour chaque orientation, elle va ensuite balayer toute l'image,
19 * **angle** : orientation de balayage
20 * **fin** : pour le balayage de l'image à une orientation donnee,
21 le segment part d'un bord, fin désigne le dernier pixel
22 du contour à envisager avec cette orientation
23 * **vecteur** : vecteur directeur correspondant à angle
24 * **bord1** : numero du bord (0,1,2,3) correspondant à ``self.a``,
25 0 bord droit, 1 bord haut, 2 bord gauche, 3 bord bas
26 * **dangle** : orientation à visiter 0, dangle, 2*dangle, 3*dangle, ...
28 Pour parcourir les segments de l'image, on part d'un premier segment
29 (methode premier), segment horizontal, bord 0,
30 la méthode next passe au segment suivant jusqu'au dernier auquel
31 cas la methode retourne *False*.
32 Les segments sont orientés, si un gradient est proche du vecteur
33 normal, l'opposé ne l'est pas.
34 """
36 # voir la remarque de la classe Point a propos de __slots__
37 __slots__ = "angle", "fin", "vecteur", "bord1", "dangle"
39 def __init__(self, dim, dangle=math.pi / 24.0):
40 """initialise les dimensions et
41 fait sorte que la classe contienne le premier segment"""
42 SegmentBord_Commun.__init__(self, dim)
43 self.premier()
44 self.dangle = dangle
46 def __str__(self):
47 """permet d'afficher le segment"""
48 s = SegmentBord_Commun.__str__(self)
49 s += " -- bord " + str(self.bord1)
50 s += " -- fin " + str(self.fin)
51 s += " -- a " + f"{self.angle * 180 / math.pi:3.1f}"
52 s += " -- vec " + f"{self.vecteur.x:2.2f},{self.vecteur.y:2.2f}"
53 return s
55 def premier(self):
56 """définit le premier segment, horizontal, part du bord gauche"""
57 self.angle = 0
58 self.fin = Point(0, 0)
59 self.calcul_vecteur()
61 def milieu(self):
62 """
63 Un autre segment, pour débugger le programme,
64 choisit une orientation pour laquelle on sait que le
65 résultat doit être un segment significatif,
66 la methode *next* ira plus vite au dernier segment.
67 """
68 self.angle = math.pi / 2
69 self.calcul_vecteur()
71 def calcul_vecteur(self):
72 """
73 En fonction de l'angle, calcule le vecteur direction du segment,
74 ensuite fixe la première extrémité du segment ``self.a``
75 et détermine la dernière des premières extremités pour
76 un segment de cette orientation (angle).
77 """
78 self.vecteur = Point(math.cos(self.angle), math.sin(self.angle))
80 # le vecteur est horizontal
81 if abs(self.vecteur.x) < 1e-5:
82 if self.vecteur.y > 0:
83 # vers le haut, un seul bord pour la premiere extremite
84 self.bord1 = 3
85 self.a.x = 0
86 self.a.y = 0
87 self.fin.x = self.dim.x - 1
88 self.fin.y = 0
89 return self.calcul_vecteur_fin()
90 else:
91 # vers le bas, un seul bord pour la premiere extremite
92 self.bord1 = 1
93 self.a.x = self.dim.x - 1
94 self.a.y = self.dim.y - 1
95 self.fin.x = 0
96 self.fin.y = self.dim.y - 1
97 return self.calcul_vecteur_fin()
99 # le vecteur est vertical
100 if abs(self.vecteur.y) < 1e-5:
101 if self.vecteur.x < 0:
102 # vers la droite, un seul bord pour la premiere extremite
103 self.bord1 = 0
104 self.a.x = self.dim.x - 1
105 self.a.y = 0
106 self.fin.x = self.dim.x - 1
107 self.fin.y = self.dim.y - 1
108 return self.calcul_vecteur_fin()
109 else:
110 # vers la gauche, un seul bord pour la premiere extremite
111 self.bord1 = 2
112 self.a.x = 0
113 self.a.y = self.dim.y - 1
114 self.fin.x = 0
115 self.fin.y = 0
116 return self.calcul_vecteur_fin()
118 if self.vecteur.x < 0:
119 if self.vecteur.y < 0:
120 # en bas a gauche, deux bords pour la premiere extremite
121 self.bord1 = 0
122 self.a.x = self.dim.x - 1
123 self.a.y = 0
124 self.fin.x = 0
125 self.fin.y = self.dim.y - 1
126 return self.calcul_vecteur_fin()
127 else:
128 # en haut a gauche, deux bords pour la premiere extremite
129 self.bord1 = 3
130 self.a.x = 0
131 self.a.y = 0
132 self.fin.x = self.dim.x - 1
133 self.fin.y = self.dim.y - 1
134 return self.calcul_vecteur_fin()
135 else:
136 if self.vecteur.y < 0:
137 # en haut a droite, deux bords pour la premiere extremite
138 self.bord1 = 1
139 self.a.x = self.dim.x - 1
140 self.a.y = self.dim.y - 1
141 self.fin.x = 0
142 self.fin.y = 0
143 return self.calcul_vecteur_fin()
144 else:
145 # en bas a droite, deux bords pour la premiere extremite
146 self.bord1 = 2
147 self.a.x = 0
148 self.a.y = self.dim.y - 1
149 self.fin.x = self.dim.x - 1
150 self.fin.y = 0
151 return self.calcul_vecteur_fin()
153 def calcul_vecteur_fin(self):
154 """propose une seconde extrémité connaissant la première,
155 beaucoup plus loin en conservant la meme orientation,
156 du moment qu'on traverse l'image"""
157 t = self.dim.x + self.dim.y
158 self.b.x = int(self.a.x + self.vecteur.x * t)
159 self.b.y = int(self.a.y + self.vecteur.y * t)
161 def directeur(self):
162 """retourne une copie du vecteur directeur"""
163 return copy.copy(self.vecteur)
165 def next(self):
166 """passe au segment suivant dans le parcours de l'image"""
168 if self.angle >= math.pi * 2 - 1e-5:
169 # toute orientation visitee
170 return False
172 if self.a == self.fin:
173 # tout vecteur visitee pour la meme orientation,
174 # on passe a l'orientation suivante
175 self.angle += self.dangle
176 self.calcul_vecteur()
177 if self.angle >= math.pi * 2:
178 return False
179 else:
180 return True
181 else:
182 # on passe au segment suivant selon la meme orientation,
183 # tout depend du bord sur lequel on est
184 if self.bord1 == 0:
185 # bord droit
186 if self.a.y < self.dim.y - 1:
187 # pas besoin de changer de bord
188 self.a.y += 1
189 else:
190 # on passe au bord suivant, bord haut
191 self.bord1 = 1
192 self.a.x -= 1
193 elif self.bord1 == 1:
194 # bord haut, meme raisonnement que pour le premier bord
195 if self.a.x > 0:
196 self.a.x -= 1
197 else:
198 self.bord1 = 2
199 self.a.y -= 1
200 elif self.bord1 == 2:
201 # bord gauche, meme raisonnement que pour le premier bord
202 if self.a.y > 0:
203 self.a.y -= 1
204 else:
205 self.bord1 = 3
206 self.a.x += 1
207 elif self.bord1 == 3:
208 # bord bas, meme raisonnement que pour le premier bord
209 if self.a.x < self.dim.x - 1:
210 self.a.x += 1
211 else:
212 self.bord1 = 0
213 self.a.y += 1
214 # choisit une derniere extremite
215 self.calcul_vecteur_fin()
216 return True
218 def calcul_bord2(self):
219 """calcule précisément la second extrémité, parcourt la demi-droite
220 jusqu'à sortir de l'image, le dernier point est la seconde extrémité"""
221 a = self.a.arrondi()
222 p = copy.copy(self.a)
223 n = self.directeur()
225 i = 0
226 while a.x >= 0 and a.y >= 0 and a.x < self.dim.x and a.y < self.dim.y:
227 p += n
228 a = p.arrondi()
229 i += 1
231 self.b.x = a.x
232 self.b.y = a.y
233 r = -1
234 if self.b.x < 0:
235 self.b.x = 0
236 r = 2
237 if self.b.x >= self.dim.x:
238 self.b.x = self.dim.x - 1
239 r = 0
240 if self.b.y < 0:
241 self.b.y = 0
242 r = 3
243 if self.b.y >= self.dim.y:
244 self.b.y = self.dim.y - 1
245 r = 1
246 return r