changeset 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 5e00ed18ae32
children 5d22498c73d1
files transformations/Rature.py
diffstat 1 files changed, 188 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/transformations/Rature.py	Wed Feb 17 17:45:48 2010 -0500
+++ b/transformations/Rature.py	Thu Feb 18 10:53:36 2010 -0500
@@ -2,15 +2,12 @@
 # coding: utf-8
 
 '''
-Ajout de rature sur le caractère. La rature peut etre horizontale, verticale 
-(dans ces deux cas, l'amplacement de la bande est aleatoire) ou sur la diagonale
-(et anti-diagonale).
+Ajout d'une rature sur le caractère. La rature est en fait un 1 qui recoit une
+rotation et qui est ensuite appliqué sur le caractère. Un grossissement, puis deux
+erosions sont effectuees sur le 1 afin qu'il ne soit plus reconnaissable.
+Il y a des chances d'avoir plus d'une seule rature !
 
-La largeur de la bande ainsi que sa clarté sont definies a l'aide de complexity
-et d'une composante aleatoire.
-clarte: 0=blanc et 1=noir
-
-Il y a 15% d'effectuer une rature
+Il y a 15% d'effectuer une rature.
 
 Ce fichier prend pour acquis que les images sont donnees une a la fois
 sous forme de numpy.array de 1024 (32 x 32) valeurs entre 0 et 1.
@@ -19,95 +16,196 @@
 
 '''
 
-import numpy
+import numpy, Image, random
+import scipy.ndimage.morphology
+from pylearn.io import filetensor as ft
 
 
 class Rature():
    
     def __init__(self):
-        self.largeur=2  #Largeur de la bande
-        self.deplacement=0  #Deplacement par rapport au milieu
-        self.orientation=0  #0=horizontal, 1=vertical, 2=oblique
-        self.clarte=0.5 #Clarte de la ligne appliquee
-        self.faire=1  #Si ==1, on applique une rature
+        self.angle=0 #Angle en degre de la rotation (entre 0 et 180)
+        self.numero=0 #Le numero du 1 choisi dans la banque de 1
+        self.gauche=-1   #Le numero de la colonne la plus a gauche contenant le 1
+        self.droite=-1
+        self.haut=-1
+        self.bas=-1
+        self.faire=1    #1=on effectue et 0=fait rien
+        
+        self.crop_haut=0
+        self.crop_gauche=0  #Ces deux valeurs sont entre 0 et 31 afin de definir
+                            #l'endroit ou sera pris le crop dans l'image du 1
+                            
+        self.largeur_bande=-1    #La largeur de la bande
+        self.smooth=-1   #La largeur de la matrice carree servant a l'erosion
+        self.nb_ratures=-1   #Le nombre de ratures appliques
+        self.fini=0 #1=fini de mettre toutes les couches 0=pas fini
+        self.complexity=0   #Pour garder en memoire la complexite si plusieurs couches sont necessaires
+        
+        f3 = open('/data/lisa/data/ift6266h10/un_rature.ft')   #Doit etre sur le reseau DIRO.
+        #f3 = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/un_rature.ft')
+        #Il faut arranger le path sinon
+        w=ft.read(f3)
+        f3.close()
+        self.d=(w.astype('float'))/255
+        
+        self.patch=self.d[0].reshape((32,32)) #La patch de rature qui sera appliquee sur l'image
 
     def get_settings_names(self):
-        return ['orientation','deplacement','clarte','faire']
+        return ['angle','numero','faire','crop_haut','crop_gauche','largeur_bande','smooth','nb_ratures']
 
     def regenerate_parameters(self, complexity):
-        #Il faut choisir parmis vertical, horizontal et diagonal.
-        #La methode n'est pas exacte, mais un peu plus rapide que generer un int.
-        #Complexity n'a rien a voir avec ce choix
+        
         
-        choix=numpy.random.random()
-        
-        if choix <0.34:
-            self.orientation=0
-        elif choix <0.67:
-            self.orientation=1
+        self.numero=random.randint(0,4999)  #Ces bornes sont inclusives !
+        self.fini=0
+        self.complexity=complexity
+            
+        if float(complexity) > 0:
+            
+            self.gauche=self.droite=self.haut=self.bas=-1   #Remet tout a -1
+            
+            self.angle=int(numpy.random.normal(90,100*complexity))
+
+            self.faire=numpy.random.binomial(1,0.15)    ##### 15% d'effectuer une rature #####
+            #self.faire=1 #Pour tester seulement
+            
+            self.crop_haut=random.randint(0,17)
+            self.crop_gauche=random.randint(0,17)
+            if complexity <= 0.25 :
+                self.smooth=6
+            elif complexity <= 0.5:
+                self.smooth=5
+            elif complexity <= 0.75:
+                self.smooth=4
+            else:
+                self.smooth=3
+            self.nb_ratures=int(numpy.random.normal(complexity*2,complexity*1.5))+1
+            
+            #Creation de la "patch" de rature qui sera appliquee sur l'image
+            if self.faire == 1:
+                self.get_size()
+                self.get_image_rot()    #On fait la "patch"
+            
         else:
-            self.orientation=2
-            
-        if float(complexity) > 0:    
-            self.largeur=min(32,max(1,int(numpy.ceil(complexity*5)*numpy.random.normal(1,float(complexity)/2))))
-            self.clarte=min(1,max(0,complexity*numpy.random.normal(1,float(complexity)/2)))
-            self.faire=numpy.random.binomial(1,0.15)    ##### 15% d'effectuer une rature #####
-        else:
-            self.largeur=0
-            self.clarte=0
-            self.faire=0    #On ne fait rien !!!
+            self.faire=0    #On ne fait rien si complexity=0 !!
         
         return self._get_current_parameters()
+    
+    
+    def get_image_rot(self):
+        image2=(self.d[self.numero].reshape((32,32))[self.haut:self.bas,self.gauche:self.droite])
+        
+        im = Image.fromarray(numpy.asarray(image2*255,dtype='uint8'))
+        
+        #La rotation et le resize sont de belle qualite afin d'avoir une image nette
+        im2 = im.rotate(self.angle,Image.BICUBIC,expand=False)
+        im3=im2.resize((50,50),Image.ANTIALIAS)
+        
+        grosse=numpy.asarray(numpy.asarray(im3)/255.0,dtype='float32')
+        crop=grosse[self.haut:self.haut+32,self.gauche:self.gauche+32]
+        
+        self.get_patch(crop)
+        
+    def get_patch(self,crop):
+        
+        
+        smooting=numpy.zeros((self.smooth,self.smooth))+1  #Au plus c'est gros, au plus ca rapetisse la ligne
+
+        #Il y a deux erosions afin d'avoir un beau resultat. Pas trop large et
+        #pas trop mince
+        trans=scipy.ndimage.morphology.grey_erosion\
+                    (crop,size=smooting.shape,structure=smooting,mode='wrap')
+        trans1=scipy.ndimage.morphology.grey_erosion\
+                    (trans,size=smooting.shape,structure=smooting,mode='wrap')
+        
+               
+        patch_img=Image.fromarray(numpy.asarray(trans1*255,dtype='uint8'))
+        
+        patch_img2=patch_img.crop((4,4,28,28)).resize((32,32))  #Pour contrer les effets de bords !
+        
+        trans2=numpy.asarray(numpy.asarray(patch_img2)/255.0,dtype='float32')
+            
+            
+        #Tout ramener entre 0 et 1
+        trans2=trans2-trans2.min() #On remet tout positif
+        trans2=trans2/trans2.max()
+        
+        #La rayure a plus de chance d'etre en bas ou oblique le haut a 10h
+        if random.random() <= 0.5:  #On renverse la matrice dans ce cas
+            for i in xrange(0,32):
+                self.patch[i,:]=trans2[31-i,:]
+        else:
+            self.patch=trans2
+        
+    
+    
+    
+    def get_size(self):
+        image=self.d[self.numero].reshape((32,32))
+        
+        #haut
+        for i in xrange(0,32):
+            for j in xrange(0,32):
+                if(image[i,j]) != 0:
+                    if self.haut == -1:
+                        self.haut=i
+                        break
+            if self.haut > -1:
+                break
+        
+        #bas
+        for i in xrange(31,-1,-1):
+            for j in xrange(0,32):
+                if(image[i,j]) != 0:
+                    if self.bas == -1:
+                        self.bas=i
+                        break
+            if self.bas > -1:
+                break
+            
+        #gauche
+        for i in xrange(0,32):
+            for j in xrange(0,32):
+                if(image[j,i]) != 0:
+                    if self.gauche == -1:
+                        self.gauche=i
+                        break
+            if self.gauche > -1:
+                break
+            
+        #droite
+        for i in xrange(31,-1,-1):
+            for j in xrange(0,32):
+                if(image[j,i]) != 0:
+                    if self.droite == -1:
+                        self.droite=i
+                        break
+            if self.droite > -1:
+                break
+                
 
     def _get_current_parameters(self):
-        return [self.orientation,self.largeur,self.clarte,self.faire]
+        return [self.angle,self.numero,self.faire,self.crop_haut,self.crop_gauche,self.largeur_bande,self.smooth,self.nb_ratures]
 
     def transform_image(self, image):
-        if self.faire == 0:
+        if self.faire == 0: #Rien faire !!
             return image
         
-        if self.orientation == 0:
-            return self._horizontal(image)
-        elif self.orientation == 1:
-            return self._vertical(image)
-        else:
-            return self._oblique(image)
-        
-    def _horizontal(self,image):
-        self.deplacement=numpy.random.normal(0,5)
-        #On s'assure de rester dans l'image
-        if self.deplacement < -16:  #Si on recule trop
-            self.deplacement = -16
-        if self.deplacement+self.largeur > 16: #Si on avance trop
-            self.deplacement=16-self.largeur
-        for i in xrange(0,self.largeur):
-            for j in xrange(0,32):
-                image[i+15+self.deplacement,j]=min(1,max(image[i+15+self.deplacement,j],self.clarte))
-        return image
-    
-    def _vertical(self,image):
-        self.deplacement=numpy.random.normal(0,5)
-        #On s'assure de rester dans l'image
-        if self.deplacement < -16:  #Si on recule trop
-            self.deplacement = -16
-        if self.deplacement+self.largeur > 16: #Si on avance trop
-            self.deplacement=16-self.largeur
-        for i in xrange(0,self.largeur):
-            for j in xrange(0,32):
-                image[j,i+15+self.deplacement]=min(1,max(image[j,i+15+self.deplacement],self.clarte))
-        return image
-    
-    def _oblique(self,image):
-        decision=numpy.random.random()
-        D=numpy.zeros((32,32)) #La matrice qui sera additionnee
-        for i in xrange(int(-numpy.floor(self.largeur/2)),int(numpy.ceil((self.largeur+1)/2))):
-            D+=numpy.eye(32,32,i)
-        if decision<0.5: #On met tout sur l'anti-diagonale
-            D = D[:,::-1]
-        D*=self.clarte
+        if self.fini == 0:   #S'il faut rajouter des couches
+            patch_temp=self.patch
+            for w in xrange(1,self.nb_ratures):
+                self.regenerate_parameters(self.complexity)
+                for i in xrange(0,32):
+                    for j in xrange(0,32):
+                        patch_temp[i,j]=max(patch_temp[i,j],self.patch[i,j])
+            self.fini=1
+            self.patch=patch_temp
+            
         for i in xrange(0,32):
             for j in xrange(0,32):
-                image[i,j]=min(1,max(image[i,j],D[i,j])) 
+                image[i,j]=max(image[i,j],self.patch[i,j])
+        self.patch*=0   #Remise a zero de la patch (pas necessaire)
         return image
 
 
@@ -116,27 +214,29 @@
 def _load_image():
     f = open('/home/sylvain/Dropbox/Msc/IFT6266/donnees/lower_test_data.ft')  #Le jeu de donnees est en local. 
     d = ft.read(f)
-    w=numpy.asarray(d[1])
+    w=numpy.asarray(d[0:1000])
     return (w/255.0).astype('float')
 
 def _test(complexite):
     img=_load_image()
     transfo = Rature()
-    pylab.imshow(img.reshape((32,32)))
-    pylab.show()
-    print transfo.get_settings_names()
-    print transfo.regenerate_parameters(complexite)
-    img=img.reshape((32,32))
-    
-    img_trans=transfo.transform_image(img)
-    
-    pylab.imshow(img_trans.reshape((32,32)))
-    pylab.show()
+    for i in xrange(0,10):
+        img2=img[random.randint(0,1000)]
+        pylab.imshow(img2.reshape((32,32)))
+        pylab.show()
+        print transfo.get_settings_names()
+        print transfo.regenerate_parameters(complexite)
+        img2=img2.reshape((32,32))
+        
+        img2_trans=transfo.transform_image(img2)
+        
+        pylab.imshow(img2_trans.reshape((32,32)))
+        pylab.show()
     
 
 if __name__ == '__main__':
     from pylearn.io import filetensor as ft
     import pylab
-    _test(0.8)
+    _test(1)