Mercurial > ift6266
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 |