comparison transformations/Rature.py @ 121:4a29910eae93

Maintenant, les ratures sont fabriquees a partir de 1 qui ont ete transformes pas mal. Les ratures peuvent maintenant etre plus d'une. Proba 0.15 d'effectuer une rature
author SylvainPL <sylvain.pannetier.lebeuf@umontreal.ca>
date Thu, 18 Feb 2010 10:53:36 -0500
parents 9e5463ebd044
children 5d3a7a4e30e9
comparison
equal deleted inserted replaced
120:5e00ed18ae32 121:4a29910eae93
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # coding: utf-8 2 # coding: utf-8
3 3
4 ''' 4 '''
5 Ajout de rature sur le caractère. La rature peut etre horizontale, verticale 5 Ajout d'une rature sur le caractère. La rature est en fait un 1 qui recoit une
6 (dans ces deux cas, l'amplacement de la bande est aleatoire) ou sur la diagonale 6 rotation et qui est ensuite appliqué sur le caractère. Un grossissement, puis deux
7 (et anti-diagonale). 7 erosions sont effectuees sur le 1 afin qu'il ne soit plus reconnaissable.
8 8 Il y a des chances d'avoir plus d'une seule rature !
9 La largeur de la bande ainsi que sa clarté sont definies a l'aide de complexity 9
10 et d'une composante aleatoire. 10 Il y a 15% d'effectuer une rature.
11 clarte: 0=blanc et 1=noir
12
13 Il y a 15% d'effectuer une rature
14 11
15 Ce fichier prend pour acquis que les images sont donnees une a la fois 12 Ce fichier prend pour acquis que les images sont donnees une a la fois
16 sous forme de numpy.array de 1024 (32 x 32) valeurs entre 0 et 1. 13 sous forme de numpy.array de 1024 (32 x 32) valeurs entre 0 et 1.
17 14
18 Sylvain Pannetier Lebeuf dans le cadre de IFT6266, hiver 2010 15 Sylvain Pannetier Lebeuf dans le cadre de IFT6266, hiver 2010
19 16
20 ''' 17 '''
21 18
22 import numpy 19 import numpy, Image, random
20 import scipy.ndimage.morphology
21 from pylearn.io import filetensor as ft
23 22
24 23
25 class Rature(): 24 class Rature():
26 25
27 def __init__(self): 26 def __init__(self):
28 self.largeur=2 #Largeur de la bande 27 self.angle=0 #Angle en degre de la rotation (entre 0 et 180)
29 self.deplacement=0 #Deplacement par rapport au milieu 28 self.numero=0 #Le numero du 1 choisi dans la banque de 1
30 self.orientation=0 #0=horizontal, 1=vertical, 2=oblique 29 self.gauche=-1 #Le numero de la colonne la plus a gauche contenant le 1
31 self.clarte=0.5 #Clarte de la ligne appliquee 30 self.droite=-1
32 self.faire=1 #Si ==1, on applique une rature 31 self.haut=-1
32 self.bas=-1
33 self.faire=1 #1=on effectue et 0=fait rien
34
35 self.crop_haut=0
36 self.crop_gauche=0 #Ces deux valeurs sont entre 0 et 31 afin de definir
37 #l'endroit ou sera pris le crop dans l'image du 1
38
39 self.largeur_bande=-1 #La largeur de la bande
40 self.smooth=-1 #La largeur de la matrice carree servant a l'erosion
41 self.nb_ratures=-1 #Le nombre de ratures appliques
42 self.fini=0 #1=fini de mettre toutes les couches 0=pas fini
43 self.complexity=0 #Pour garder en memoire la complexite si plusieurs couches sont necessaires
44
45 f3 = open('/data/lisa/data/ift6266h10/un_rature.ft') #Doit etre sur le reseau DIRO.
46 #f3 = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/un_rature.ft')
47 #Il faut arranger le path sinon
48 w=ft.read(f3)
49 f3.close()
50 self.d=(w.astype('float'))/255
51
52 self.patch=self.d[0].reshape((32,32)) #La patch de rature qui sera appliquee sur l'image
33 53
34 def get_settings_names(self): 54 def get_settings_names(self):
35 return ['orientation','deplacement','clarte','faire'] 55 return ['angle','numero','faire','crop_haut','crop_gauche','largeur_bande','smooth','nb_ratures']
36 56
37 def regenerate_parameters(self, complexity): 57 def regenerate_parameters(self, complexity):
38 #Il faut choisir parmis vertical, horizontal et diagonal. 58
39 #La methode n'est pas exacte, mais un peu plus rapide que generer un int. 59
40 #Complexity n'a rien a voir avec ce choix 60 self.numero=random.randint(0,4999) #Ces bornes sont inclusives !
41 61 self.fini=0
42 choix=numpy.random.random() 62 self.complexity=complexity
43 63
44 if choix <0.34: 64 if float(complexity) > 0:
45 self.orientation=0 65
46 elif choix <0.67: 66 self.gauche=self.droite=self.haut=self.bas=-1 #Remet tout a -1
47 self.orientation=1 67
68 self.angle=int(numpy.random.normal(90,100*complexity))
69
70 self.faire=numpy.random.binomial(1,0.15) ##### 15% d'effectuer une rature #####
71 #self.faire=1 #Pour tester seulement
72
73 self.crop_haut=random.randint(0,17)
74 self.crop_gauche=random.randint(0,17)
75 if complexity <= 0.25 :
76 self.smooth=6
77 elif complexity <= 0.5:
78 self.smooth=5
79 elif complexity <= 0.75:
80 self.smooth=4
81 else:
82 self.smooth=3
83 self.nb_ratures=int(numpy.random.normal(complexity*2,complexity*1.5))+1
84
85 #Creation de la "patch" de rature qui sera appliquee sur l'image
86 if self.faire == 1:
87 self.get_size()
88 self.get_image_rot() #On fait la "patch"
89
48 else: 90 else:
49 self.orientation=2 91 self.faire=0 #On ne fait rien si complexity=0 !!
50 92
51 if float(complexity) > 0: 93 return self._get_current_parameters()
52 self.largeur=min(32,max(1,int(numpy.ceil(complexity*5)*numpy.random.normal(1,float(complexity)/2)))) 94
53 self.clarte=min(1,max(0,complexity*numpy.random.normal(1,float(complexity)/2))) 95
54 self.faire=numpy.random.binomial(1,0.15) ##### 15% d'effectuer une rature ##### 96 def get_image_rot(self):
97 image2=(self.d[self.numero].reshape((32,32))[self.haut:self.bas,self.gauche:self.droite])
98
99 im = Image.fromarray(numpy.asarray(image2*255,dtype='uint8'))
100
101 #La rotation et le resize sont de belle qualite afin d'avoir une image nette
102 im2 = im.rotate(self.angle,Image.BICUBIC,expand=False)
103 im3=im2.resize((50,50),Image.ANTIALIAS)
104
105 grosse=numpy.asarray(numpy.asarray(im3)/255.0,dtype='float32')
106 crop=grosse[self.haut:self.haut+32,self.gauche:self.gauche+32]
107
108 self.get_patch(crop)
109
110 def get_patch(self,crop):
111
112
113 smooting=numpy.zeros((self.smooth,self.smooth))+1 #Au plus c'est gros, au plus ca rapetisse la ligne
114
115 #Il y a deux erosions afin d'avoir un beau resultat. Pas trop large et
116 #pas trop mince
117 trans=scipy.ndimage.morphology.grey_erosion\
118 (crop,size=smooting.shape,structure=smooting,mode='wrap')
119 trans1=scipy.ndimage.morphology.grey_erosion\
120 (trans,size=smooting.shape,structure=smooting,mode='wrap')
121
122
123 patch_img=Image.fromarray(numpy.asarray(trans1*255,dtype='uint8'))
124
125 patch_img2=patch_img.crop((4,4,28,28)).resize((32,32)) #Pour contrer les effets de bords !
126
127 trans2=numpy.asarray(numpy.asarray(patch_img2)/255.0,dtype='float32')
128
129
130 #Tout ramener entre 0 et 1
131 trans2=trans2-trans2.min() #On remet tout positif
132 trans2=trans2/trans2.max()
133
134 #La rayure a plus de chance d'etre en bas ou oblique le haut a 10h
135 if random.random() <= 0.5: #On renverse la matrice dans ce cas
136 for i in xrange(0,32):
137 self.patch[i,:]=trans2[31-i,:]
55 else: 138 else:
56 self.largeur=0 139 self.patch=trans2
57 self.clarte=0 140
58 self.faire=0 #On ne fait rien !!! 141
59 142
60 return self._get_current_parameters() 143
144 def get_size(self):
145 image=self.d[self.numero].reshape((32,32))
146
147 #haut
148 for i in xrange(0,32):
149 for j in xrange(0,32):
150 if(image[i,j]) != 0:
151 if self.haut == -1:
152 self.haut=i
153 break
154 if self.haut > -1:
155 break
156
157 #bas
158 for i in xrange(31,-1,-1):
159 for j in xrange(0,32):
160 if(image[i,j]) != 0:
161 if self.bas == -1:
162 self.bas=i
163 break
164 if self.bas > -1:
165 break
166
167 #gauche
168 for i in xrange(0,32):
169 for j in xrange(0,32):
170 if(image[j,i]) != 0:
171 if self.gauche == -1:
172 self.gauche=i
173 break
174 if self.gauche > -1:
175 break
176
177 #droite
178 for i in xrange(31,-1,-1):
179 for j in xrange(0,32):
180 if(image[j,i]) != 0:
181 if self.droite == -1:
182 self.droite=i
183 break
184 if self.droite > -1:
185 break
186
61 187
62 def _get_current_parameters(self): 188 def _get_current_parameters(self):
63 return [self.orientation,self.largeur,self.clarte,self.faire] 189 return [self.angle,self.numero,self.faire,self.crop_haut,self.crop_gauche,self.largeur_bande,self.smooth,self.nb_ratures]
64 190
65 def transform_image(self, image): 191 def transform_image(self, image):
66 if self.faire == 0: 192 if self.faire == 0: #Rien faire !!
67 return image 193 return image
68 194
69 if self.orientation == 0: 195 if self.fini == 0: #S'il faut rajouter des couches
70 return self._horizontal(image) 196 patch_temp=self.patch
71 elif self.orientation == 1: 197 for w in xrange(1,self.nb_ratures):
72 return self._vertical(image) 198 self.regenerate_parameters(self.complexity)
73 else: 199 for i in xrange(0,32):
74 return self._oblique(image) 200 for j in xrange(0,32):
75 201 patch_temp[i,j]=max(patch_temp[i,j],self.patch[i,j])
76 def _horizontal(self,image): 202 self.fini=1
77 self.deplacement=numpy.random.normal(0,5) 203 self.patch=patch_temp
78 #On s'assure de rester dans l'image 204
79 if self.deplacement < -16: #Si on recule trop
80 self.deplacement = -16
81 if self.deplacement+self.largeur > 16: #Si on avance trop
82 self.deplacement=16-self.largeur
83 for i in xrange(0,self.largeur):
84 for j in xrange(0,32):
85 image[i+15+self.deplacement,j]=min(1,max(image[i+15+self.deplacement,j],self.clarte))
86 return image
87
88 def _vertical(self,image):
89 self.deplacement=numpy.random.normal(0,5)
90 #On s'assure de rester dans l'image
91 if self.deplacement < -16: #Si on recule trop
92 self.deplacement = -16
93 if self.deplacement+self.largeur > 16: #Si on avance trop
94 self.deplacement=16-self.largeur
95 for i in xrange(0,self.largeur):
96 for j in xrange(0,32):
97 image[j,i+15+self.deplacement]=min(1,max(image[j,i+15+self.deplacement],self.clarte))
98 return image
99
100 def _oblique(self,image):
101 decision=numpy.random.random()
102 D=numpy.zeros((32,32)) #La matrice qui sera additionnee
103 for i in xrange(int(-numpy.floor(self.largeur/2)),int(numpy.ceil((self.largeur+1)/2))):
104 D+=numpy.eye(32,32,i)
105 if decision<0.5: #On met tout sur l'anti-diagonale
106 D = D[:,::-1]
107 D*=self.clarte
108 for i in xrange(0,32): 205 for i in xrange(0,32):
109 for j in xrange(0,32): 206 for j in xrange(0,32):
110 image[i,j]=min(1,max(image[i,j],D[i,j])) 207 image[i,j]=max(image[i,j],self.patch[i,j])
208 self.patch*=0 #Remise a zero de la patch (pas necessaire)
111 return image 209 return image
112 210
113 211
114 #---TESTS--- 212 #---TESTS---
115 213
116 def _load_image(): 214 def _load_image():
117 f = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/lower_test_data.ft') #Le jeu de donnees est en local. 215 f = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/lower_test_data.ft') #Le jeu de donnees est en local.
118 d = ft.read(f) 216 d = ft.read(f)
119 w=numpy.asarray(d[1]) 217 w=numpy.asarray(d[0:1000])
120 return (w/255.0).astype('float') 218 return (w/255.0).astype('float')
121 219
122 def _test(complexite): 220 def _test(complexite):
123 img=_load_image() 221 img=_load_image()
124 transfo = Rature() 222 transfo = Rature()
125 pylab.imshow(img.reshape((32,32))) 223 for i in xrange(0,10):
126 pylab.show() 224 img2=img[random.randint(0,1000)]
127 print transfo.get_settings_names() 225 pylab.imshow(img2.reshape((32,32)))
128 print transfo.regenerate_parameters(complexite) 226 pylab.show()
129 img=img.reshape((32,32)) 227 print transfo.get_settings_names()
130 228 print transfo.regenerate_parameters(complexite)
131 img_trans=transfo.transform_image(img) 229 img2=img2.reshape((32,32))
132 230
133 pylab.imshow(img_trans.reshape((32,32))) 231 img2_trans=transfo.transform_image(img2)
134 pylab.show() 232
233 pylab.imshow(img2_trans.reshape((32,32)))
234 pylab.show()
135 235
136 236
137 if __name__ == '__main__': 237 if __name__ == '__main__':
138 from pylearn.io import filetensor as ft 238 from pylearn.io import filetensor as ft
139 import pylab 239 import pylab
140 _test(0.8) 240 _test(1)
141 241
142 242