comparison transformations/Rature.py @ 144:c958941c1b9d

merge
author XavierMuller
date Tue, 23 Feb 2010 18:16:55 -0500
parents a507adba0ce3
children 51b531226557
comparison
equal deleted inserted replaced
143:f341a4efb44a 144:c958941c1b9d
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,next_rature = False):
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 if next_rature:
72 self.faire = 1
73 #self.faire=1 #Pour tester seulement
74
75 self.crop_haut=random.randint(0,17)
76 self.crop_gauche=random.randint(0,17)
77 if complexity <= 0.25 :
78 self.smooth=6
79 elif complexity <= 0.5:
80 self.smooth=5
81 elif complexity <= 0.75:
82 self.smooth=4
83 else:
84 self.smooth=3
85
86 p = numpy.random.rand()
87 if p < 0.5:
88 self.nb_ratures= 1
89 else:
90 if p < 0.8:
91 self.nb_ratures = 2
92 else:
93 self.nb_ratures = 3
94
95 #Creation de la "patch" de rature qui sera appliquee sur l'image
96 if self.faire == 1:
97 self.get_size()
98 self.get_image_rot() #On fait la "patch"
99
48 else: 100 else:
49 self.orientation=2 101 self.faire=0 #On ne fait rien si complexity=0 !!
50 102
51 if float(complexity) > 0: 103 return self._get_current_parameters()
52 self.largeur=min(32,max(1,int(numpy.ceil(complexity*5)*numpy.random.normal(1,float(complexity)/2)))) 104
53 self.clarte=min(1,max(0,complexity*numpy.random.normal(1,float(complexity)/2))) 105
54 self.faire=numpy.random.binomial(1,0.15) ##### 15% d'effectuer une rature ##### 106 def get_image_rot(self):
107 image2=(self.d[self.numero].reshape((32,32))[self.haut:self.bas,self.gauche:self.droite])
108
109 im = Image.fromarray(numpy.asarray(image2*255,dtype='uint8'))
110
111 #La rotation et le resize sont de belle qualite afin d'avoir une image nette
112 im2 = im.rotate(self.angle,Image.BICUBIC,expand=False)
113 im3=im2.resize((50,50),Image.ANTIALIAS)
114
115 grosse=numpy.asarray(numpy.asarray(im3)/255.0,dtype='float32')
116 crop=grosse[self.haut:self.haut+32,self.gauche:self.gauche+32]
117
118 self.get_patch(crop)
119
120 def get_patch(self,crop):
121 smooting = numpy.ones((self.smooth,self.smooth))
122 #Il y a deux erosions afin d'avoir un beau resultat. Pas trop large et
123 #pas trop mince
124 trans=scipy.ndimage.morphology.grey_erosion\
125 (crop,size=smooting.shape,structure=smooting,mode='wrap')
126 trans1=scipy.ndimage.morphology.grey_erosion\
127 (trans,size=smooting.shape,structure=smooting,mode='wrap')
128
129
130 patch_img=Image.fromarray(numpy.asarray(trans1*255,dtype='uint8'))
131
132 patch_img2=patch_img.crop((4,4,28,28)).resize((32,32)) #Pour contrer les effets de bords !
133
134 trans2=numpy.asarray(numpy.asarray(patch_img2)/255.0,dtype='float32')
135
136
137 #Tout ramener entre 0 et 1
138 trans2=trans2-trans2.min() #On remet tout positif
139 trans2=trans2/trans2.max()
140
141 #La rayure a plus de chance d'etre en bas ou oblique le haut a 10h
142 if random.random() <= 0.5: #On renverse la matrice dans ce cas
143 for i in xrange(0,32):
144 self.patch[i,:]=trans2[31-i,:]
55 else: 145 else:
56 self.largeur=0 146 self.patch=trans2
57 self.clarte=0 147
58 self.faire=0 #On ne fait rien !!! 148
59 149
60 return self._get_current_parameters() 150
151 def get_size(self):
152 image=self.d[self.numero].reshape((32,32))
153
154 #haut
155 for i in xrange(0,32):
156 for j in xrange(0,32):
157 if(image[i,j]) != 0:
158 if self.haut == -1:
159 self.haut=i
160 break
161 if self.haut > -1:
162 break
163
164 #bas
165 for i in xrange(31,-1,-1):
166 for j in xrange(0,32):
167 if(image[i,j]) != 0:
168 if self.bas == -1:
169 self.bas=i
170 break
171 if self.bas > -1:
172 break
173
174 #gauche
175 for i in xrange(0,32):
176 for j in xrange(0,32):
177 if(image[j,i]) != 0:
178 if self.gauche == -1:
179 self.gauche=i
180 break
181 if self.gauche > -1:
182 break
183
184 #droite
185 for i in xrange(31,-1,-1):
186 for j in xrange(0,32):
187 if(image[j,i]) != 0:
188 if self.droite == -1:
189 self.droite=i
190 break
191 if self.droite > -1:
192 break
193
61 194
62 def _get_current_parameters(self): 195 def _get_current_parameters(self):
63 return [self.orientation,self.largeur,self.clarte,self.faire] 196 return [self.angle,self.numero,self.faire,self.crop_haut,self.crop_gauche,self.largeur_bande,self.smooth,self.nb_ratures]
64 197
65 def transform_image(self, image): 198 def transform_image(self, image):
66 if self.faire == 0: 199 if self.faire == 0: #Rien faire !!
67 return image 200 return image
68 201
69 if self.orientation == 0: 202 if self.fini == 0: #S'il faut rajouter des couches
70 return self._horizontal(image) 203 patch_temp=self.patch
71 elif self.orientation == 1: 204 for w in xrange(1,self.nb_ratures):
72 return self._vertical(image) 205 self.regenerate_parameters(self.complexity,1)
73 else: 206 for i in xrange(0,32):
74 return self._oblique(image) 207 for j in xrange(0,32):
75 208 patch_temp[i,j]=max(patch_temp[i,j],self.patch[i,j])
76 def _horizontal(self,image): 209 self.fini=1
77 self.deplacement=numpy.random.normal(0,5) 210 self.patch=patch_temp
78 #On s'assure de rester dans l'image 211
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): 212 for i in xrange(0,32):
109 for j in xrange(0,32): 213 for j in xrange(0,32):
110 image[i,j]=min(1,max(image[i,j],D[i,j])) 214 image[i,j]=max(image[i,j],self.patch[i,j])
215 self.patch*=0 #Remise a zero de la patch (pas necessaire)
111 return image 216 return image
112 217
113 218
114 #---TESTS--- 219 #---TESTS---
115 220
116 def _load_image(): 221 def _load_image():
117 f = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/lower_test_data.ft') #Le jeu de donnees est en local. 222 f = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/lower_test_data.ft') #Le jeu de donnees est en local.
118 d = ft.read(f) 223 d = ft.read(f)
119 w=numpy.asarray(d[1]) 224 w=numpy.asarray(d[0:1000])
120 return (w/255.0).astype('float') 225 return (w/255.0).astype('float')
121 226
122 def _test(complexite): 227 def _test(complexite):
123 img=_load_image() 228 img=_load_image()
124 transfo = Rature() 229 transfo = Rature()
125 pylab.imshow(img.reshape((32,32))) 230 for i in xrange(0,10):
126 pylab.show() 231 img2=img[random.randint(0,1000)]
127 print transfo.get_settings_names() 232 pylab.imshow(img2.reshape((32,32)))
128 print transfo.regenerate_parameters(complexite) 233 pylab.show()
129 img=img.reshape((32,32)) 234 print transfo.get_settings_names()
130 235 print transfo.regenerate_parameters(complexite)
131 img_trans=transfo.transform_image(img) 236 img2=img2.reshape((32,32))
132 237
133 pylab.imshow(img_trans.reshape((32,32))) 238 img2_trans=transfo.transform_image(img2)
134 pylab.show() 239
240 pylab.imshow(img2_trans.reshape((32,32)))
241 pylab.show()
135 242
136 243
137 if __name__ == '__main__': 244 if __name__ == '__main__':
138 from pylearn.io import filetensor as ft 245 from pylearn.io import filetensor as ft
139 import pylab 246 import pylab
140 _test(0.8) 247 _test(1)
141 248
142 249