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

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 

11 

12 

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, 

18 

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, ... 

27 

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 """ 

35 

36 # voir la remarque de la classe Point a propos de __slots__ 

37 __slots__ = "angle", "fin", "vecteur", "bord1", "dangle" 

38 

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 

45 

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 

54 

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() 

60 

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() 

70 

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)) 

79 

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() 

98 

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() 

117 

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() 

152 

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) 

160 

161 def directeur(self): 

162 """retourne une copie du vecteur directeur""" 

163 return copy.copy(self.vecteur) 

164 

165 def next(self): 

166 """passe au segment suivant dans le parcours de l'image""" 

167 

168 if self.angle >= math.pi * 2 - 1e-5: 

169 # toute orientation visitee 

170 return False 

171 

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 

217 

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() 

224 

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 

230 

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