Browse Source

Ifs5 implementation enhancement

Yann Weber 2 years ago
parent
commit
d2068bf516
3 changed files with 122 additions and 28 deletions
  1. 68
    16
      python_rpnifs/__main__.py
  2. 13
    1
      python_rpnifs/fractdim.py
  3. 41
    11
      python_rpnifs/ifs5.py

+ 68
- 16
python_rpnifs/__main__.py View File

@@ -1,5 +1,7 @@
1 1
 #!/usr/bin/env python3
2 2
 import copy
3
+import random
4
+import multiprocessing
3 5
 
4 6
 try:
5 7
     import pyrpn
@@ -19,16 +21,24 @@ from .ifs3 import IFS3
19 21
 from .ifs4 import IFS4
20 22
 from .ifs5 import IFS5
21 23
 
24
+from .shape_score import ShapeScore
25
+
22 26
 
23 27
 #steps = 1024**2
24
-#steps=512**2
25
-steps=1024**2
28
+steps=512**2
29
+#steps=1024**2
26 30
 #steps*=4
27 31
 #steps*=10
28
-pool_sz = 30
29
-best_sz = 6
32
+
33
+#pool_sz = 30
34
+#best_sz = 6
35
+
36
+pool_sz = 32
37
+best_sz = 8
38
+
30 39
 n_mutation = 10
31 40
 outfile='/tmp/rpnifs2_%02d.png'
41
+outfile_grp='/tmp/rpnifs2_%02d_grp.png'
32 42
 #world = IFS1.get_world()
33 43
 #pool = [IFS1(init_sz=3, world=world) for _ in range(pool_sz)]
34 44
 #world = IFS2.get_world()
@@ -42,7 +52,18 @@ world = IFS5.get_world()
42 52
 pool = [IFS5(init_sz=6, world=world) for _ in range(pool_sz)]
43 53
 print('POOL ready')
44 54
 
55
+def stepper(ifs):
56
+    for _ in range(steps):
57
+        ifs.step()
58
+    return ifs
59
+
60
+def get_score(world):
61
+    shapescore = ShapeScore(world, jobs=1)
62
+    score = shapescore.score()
63
+    return score, shapescore
64
+
45 65
 generation=0
66
+mp_pool = multiprocessing.Pool(2)
46 67
 while True:
47 68
     generation+=1
48 69
     print('='*78)
@@ -52,18 +73,27 @@ while True:
52 73
     scores = []
53 74
     i=0
54 75
     #for ifs in pool:
55
-    for ifs in tqdm(pool, unit='ifs'):
56
-        i+=1
57
-        ifs.raz_world()
58
-        #for _ in tqdm(range(steps), total=steps, unit_scale=True):
59
-        for _ in range(steps):
60
-            ifs.step()
61
-
62
-        score = ifs.score()
76
+    #for ifs in tqdm(pool, unit='ifs'):
77
+    #    ifs.raz_world()
78
+    #    #for _ in tqdm(range(steps), total=steps, unit_scale=True):
79
+    #    for _ in range(steps):
80
+    #        ifs.step()
81
+    pool = [ifs for ifs in tqdm(mp_pool.imap(stepper, pool),
82
+                                total=len(pool),
83
+                                unit='ifs')]
84
+    
85
+    for i, (score,shapescore) in tqdm(enumerate(mp_pool.imap(get_score,
86
+                                                             [ifs._world for ifs in pool])),
87
+                                      unit='ifs', total=len(pool)):
88
+        ifs = pool[i]
89
+
90
+        #score = ifs.score()
63 91
         scores.append((ifs, score))
64
-        print('%02d) %5.3f %s' % (i, score, ifs))
92
+        #print('%02d) %5.3f %s' % (i, score, ifs))
93
+        print('%02d) %5.3f' % (i, score))
65 94
         im = Image.fromarray(ifs.get_image())
66 95
         im.save(outfile % i)
96
+        shapescore.result_image(outfile_grp % i)
67 97
 
68 98
         im_png = PngImageFile(outfile % i)
69 99
         metadata = PngInfo()
@@ -81,20 +111,42 @@ while True:
81 111
     for i, (ifs, score) in enumerate(best):
82 112
         print('%02d) %5.3f %s' % (i, score, ifs))
83 113
 
114
+    # Saving best
115
+    im = Image.fromarray(best[0][0].get_image())
116
+    outfile_gen = '/tmp/gen_%03d.png'
117
+    im.save(outfile_gen % generation)
118
+
119
+    im_png = PngImageFile(outfile_gen % generation)
120
+    metadata = PngInfo()
121
+    metadata.add_text('Score', '%5.3f' % score)
122
+    metadata.add_text('Generation', '%04d' % generation)
123
+    metadata.add_text('Pool_position', '%02d' % 1)
124
+    for key, text in ifs.expr_dict().items():
125
+        metadata.add_text(key, text)
126
+    im_png.save(outfile_gen % generation, pnginfo=metadata)
127
+
84 128
     # Mutating best
85 129
     pool = [b for b, _ in best]
86 130
     for ifs, _ in best:
87
-        for _ in range((pool_sz//best_sz)-1):
131
+        nmut_max = (pool_sz//best_sz)-1
132
+        for nmut in range(nmut_max):
88 133
             # needs >= IFS5
134
+            again = 0
89 135
             while True:
90
-                new = copy.copy(ifs)
91
-                new.mutation(n_mutation)
136
+                # half random mutation and half mutation by adding two IFS
137
+                if again > 5 or nmut < nmut_max / 2:
138
+                    new = copy.copy(ifs)
139
+                    new.mutation(n_mutation)
140
+                else:
141
+                    new =  ifs + random.choice(best)[0]
142
+
92 143
                 for cur in pool:
93 144
                     if cur - new == 0:
94 145
                         break
95 146
                 else:
96 147
                     pool.append(new)
97 148
                     break 
149
+                again += 1
98 150
             ###
99 151
             #new = copy.copy(ifs)
100 152
             #new.mutation(n_mutation)

+ 13
- 1
python_rpnifs/fractdim.py View File

@@ -11,10 +11,22 @@ def rgb2gray(rgb):
11 11
 
12 12
 def rgba2gray(rgba):
13 13
     """ @return a grayscale version of an RGBA "image" """
14
-    r, g, b, a = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2], rgb[:,:,3]
14
+    r, g, b, a = rgba[:,:,0], rgba[:,:,1], rgba[:,:,2], rgba[:,:,3]
15 15
     gray = (0.2989 * r + 0.5870 * g + 0.1140 * b) * (a/255)
16 16
     return gray
17 17
 
18
+def rgb2grayavg(rgb):
19
+    """ @return a grayscale version of an RGB "image" """
20
+    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
21
+    gray = (r+g+b)/3
22
+    return gray
23
+
24
+def rgba2grayavg(rgba):
25
+    """ @return a grayscale version of an RGBA "image" """
26
+    r, g, b, a = rgba[:,:,0], rgba[:,:,1], rgba[:,:,2], rgba[:,:,3]
27
+    gray = ((r + g + b)/3) * (a/255)
28
+    return gray
29
+
18 30
 def fractal_dimension(Z, threshold=None):
19 31
     ''' @return Minkowski-Bouligand dimension (computed) '''
20 32
     # Only for 2d image

+ 41
- 11
python_rpnifs/ifs5.py View File

@@ -7,14 +7,15 @@ from skimage.restoration import estimate_sigma
7 7
 
8 8
 from .expr import *
9 9
 from .fractdim import *
10
+from .shape_score import ShapeScore
10 11
 
11 12
 
12 13
 class IFS5(object):
13 14
     """ @brief 1 Variable IFS with R,G,B,A X,Y decomposition """
14 15
 
15 16
     #height=width=1024
16
-    height=width=768
17
-    #height=width=512
17
+    #height=width=768
18
+    height=width=512
18 19
 
19 20
     def __init__(self, nexpr=4, init_sz=1, world=None):
20 21
         self._nexpr = nexpr
@@ -44,8 +45,6 @@ class IFS5(object):
44 45
             for j, el in enumerate(expr):
45 46
                 res[k_fmt % (i, el_lbl[j])] = str(el)
46 47
         return res
47
-                
48
-        
49 48
 
50 49
     def _fel(self):
51 50
         el_lbl = 'XYrgba'
@@ -64,6 +63,9 @@ class IFS5(object):
64 63
         #ret._world = copy.deepcopy(self._world)
65 64
         return ret
66 65
 
66
+    def get_image(self):
67
+    	return self._world
68
+ 
67 69
     def __sub__(self, b):
68 70
         """ @return The sum of the levensthein distance between all expressions
69 71
                 of two ifs
@@ -72,9 +74,23 @@ class IFS5(object):
72 74
                          for j in range(len(b._expr[i]))])
73 75
                     for i in range(len(b._expr))])
74 76
 
75
-    def get_image(self):
76
-    	return self._world
77
- 
77
+    def __add__(self, b):
78
+        """ @return A new IFS generated from both IFS, randomly choosing
79
+            expression from both
80
+        """
81
+        if type(b) !=  type(self):
82
+            raise TypeError('Types are not IFS5 for add')
83
+
84
+        ret = IFS5(nexpr=self._nexpr, world=self._world)
85
+
86
+        rc = random.choice
87
+        rint = random.randint
88
+
89
+        ret._expr = [[copy.copy(rc([self, b])._expr[rc([i, len(self._expr)-1])][rc([j, len(ex)-1])])
90
+                      for j, e in enumerate(ex)]
91
+                     for i, ex in enumerate(self._expr)]
92
+        return ret
93
+
78 94
     def mutation(self, n=1, rand=True):
79 95
         """ @brief Apply mutation on expressions
80 96
             @param n the mutation count
@@ -134,7 +150,7 @@ class IFS5(object):
134 150
         #alpha score
135 151
         #scores += [fractal_dimension(self._world[:,:,3])]
136 152
 
137
-        gray = rgb2gray(self._world)
153
+        gray = rgba2gray(self._world)
138 154
         graysigma = estimate_sigma(gray)
139 155
         grayscore = fractal_dimension(gray)
140 156
         del(gray)
@@ -144,7 +160,14 @@ class IFS5(object):
144 160
 
145 161
         scores += [grayscore]*3
146 162
 
147
-        sigma = sum(sigmas)/len(sigmas)
163
+        sigma_zero = 0
164
+        for sig in sigmas:
165
+            if sig == 0:
166
+                sigma_zero += 1
167
+        if len(sigmas) > sigma_zero:
168
+            sigma = sum(sigmas)/(len(sigmas)-sigma_zero)
169
+        else:
170
+            sigma = 0
148 171
 
149 172
         mod = abs(scores[0]-scores[1])
150 173
         mod += abs(scores[0]-scores[2])
@@ -155,13 +178,20 @@ class IFS5(object):
155 178
 
156 179
         null_comp = 0
157 180
         for i in range(3):
158
-            null_comp += 1 if scores[i] == 0 else 0
181
+            null_comp += 1 if scores[i] <= 0 else 0
159 182
 
160 183
         if null_comp >= 2:
161 184
             score = 0
162 185
             mod *= 0.8
163 186
         else:
164
-            score = sum(scores)/len(scores)
187
+            zero_score=0
188
+            for score in scores:
189
+                if score == 0:
190
+                    zero_score += 1
191
+            if len(scores) < zero_score:
192
+                score = sum(scores)/(len(scores)-zero_score)
193
+            else:
194
+                score = 0
165 195
 
166 196
         score += mod 
167 197
 

Loading…
Cancel
Save