Aaron

Merge branch 'develop' into 'master'

NumPy optimized;



See merge request !3
@@ -68,9 +68,14 @@ @@ -68,9 +68,14 @@
68 # the pixels in the side. The faster the 'z' value goes out of bounds, the 68 # the pixels in the side. The faster the 'z' value goes out of bounds, the
69 # closer the color is to an outside pixel. 69 # closer the color is to an outside pixel.
70 # 70 #
71 -# Bugs 71 +# TODO:
72 # 72 #
73 -# - 2nd zoom level distorts image, not working as expected 73 +# - Implement "zoom path", a series of zoom center pixel coordinates
  74 +# - Add some color, make gradients easy
  75 +# - Convert to class
  76 +# - Make it fast
  77 +# - Function to convert pixels to graph coords
  78 +# - Create graph overlay
74 # 79 #
75 ### 80 ###
76 81
@@ -174,26 +179,33 @@ if __name__ == '__main__': @@ -174,26 +179,33 @@ if __name__ == '__main__':
174 179
175 for z in range(zoom_level): 180 for z in range(zoom_level):
176 181
  182 + # The length of line ad, the top of the new bounding box
177 ad = Re_res / zoom_factor 183 ad = Re_res / zoom_factor
  184 + # Calculate the new bounds of the real axis, centered about zoom_center
178 Re_min = Re_lim[1] + ((zoom_center[0] - (ad / 2)) * Re_incr) 185 Re_min = Re_lim[1] + ((zoom_center[0] - (ad / 2)) * Re_incr)
179 Re_max = Re_lim[0] - (((Re_res - zoom_center[0]) - (ad / 2)) * Re_incr) 186 Re_max = Re_lim[0] - (((Re_res - zoom_center[0]) - (ad / 2)) * Re_incr)
180 187
181 logger.debug('Re_min: %s + ((%s - (%s / 2)) * %s)', Re_lim[1], zoom_center[0], ad, Re_incr) 188 logger.debug('Re_min: %s + ((%s - (%s / 2)) * %s)', Re_lim[1], zoom_center[0], ad, Re_incr)
182 logger.debug('Re_max: %s - (((%s - %s) - (%s / 2)) * %s)', Re_lim[0], Re_res, zoom_center[0], ad, Re_incr) 189 logger.debug('Re_max: %s - (((%s - %s) - (%s / 2)) * %s)', Re_lim[0], Re_res, zoom_center[0], ad, Re_incr)
183 190
  191 + # The length of line ab, the left side of new bounding box
184 ab = Im_res / zoom_factor 192 ab = Im_res / zoom_factor
  193 + # Calculate the new bounds of the imaginary axis, centered about zoom_center
185 Im_min = Im_lim[1] + ((zoom_center[1] - (ab / 2)) * Im_incr) 194 Im_min = Im_lim[1] + ((zoom_center[1] - (ab / 2)) * Im_incr)
186 Im_max = Im_lim[0] - (((Im_res - zoom_center[1]) - (ab / 2)) * Im_incr) 195 Im_max = Im_lim[0] - (((Im_res - zoom_center[1]) - (ab / 2)) * Im_incr)
187 196
188 logger.debug('Im_min: %s + ((%s - (%s / 2)) * %s)', Im_lim[1], zoom_center[1], ab, Im_incr) 197 logger.debug('Im_min: %s + ((%s - (%s / 2)) * %s)', Im_lim[1], zoom_center[1], ab, Im_incr)
189 logger.debug('Im_max: %s - (((%s - %s) - (%s / 2)) * %s)', Im_lim[0], Im_res, zoom_center[1], ab, Im_incr) 198 logger.debug('Im_max: %s - (((%s - %s) - (%s / 2)) * %s)', Im_lim[0], Im_res, zoom_center[1], ab, Im_incr)
190 199
  200 + # Update bounds
191 Re_lim = (Re_max, Re_min) 201 Re_lim = (Re_max, Re_min)
192 Im_lim = (Im_max, Im_min) 202 Im_lim = (Im_max, Im_min)
193 203
  204 + # Calculate length of each axis
194 Re_len = abs(Re_lim[0] - Re_lim[1]) 205 Re_len = abs(Re_lim[0] - Re_lim[1])
195 Im_len = abs(Im_lim[0] - Im_lim[1]) 206 Im_len = abs(Im_lim[0] - Im_lim[1])
196 - 207 +
  208 + # Calculate the graph-size of each pixel
197 Re_incr = Re_len / Re_res 209 Re_incr = Re_len / Re_res
198 Im_incr = Im_len / Im_res 210 Im_incr = Im_len / Im_res
199 211
@@ -202,39 +214,55 @@ if __name__ == '__main__': @@ -202,39 +214,55 @@ if __name__ == '__main__':
202 # center of the frame in order to continue zooming on the desired pixel 214 # center of the frame in order to continue zooming on the desired pixel
203 zoom_center = (int(Re_res / 2), int(Im_res / 2)) 215 zoom_center = (int(Re_res / 2), int(Im_res / 2))
204 216
205 - pixels = []  
206 -  
207 logger.info('Re bounds: %s', Re_lim) 217 logger.info('Re bounds: %s', Re_lim)
208 logger.info('Im bounds: %s', Im_lim) 218 logger.info('Im bounds: %s', Im_lim)
209 logger.info('Re increment: %s', Re_incr) 219 logger.info('Re increment: %s', Re_incr)
210 logger.info('Im increment: %s', Im_incr) 220 logger.info('Im increment: %s', Im_incr)
211 221
  222 + logger.info('Initializing c values for frame')
  223 + cdata = np.zeros((Im_res, Re_res), dtype=np.complex_)
  224 + for yidx, y in enumerate(range(1, Im_res + 1)):
  225 + for xidx, x in enumerate(range(1, Re_res + 1)):
  226 +
  227 + # Calculates the value of c for each pixel on the graph
  228 + cdata[yidx,xidx] = complex(Re_lim[1] + (Re_incr * x), Im_lim[1] + (Im_incr * y))
  229 +
  230 + brot = lambda z, c: (z * z) + c
  231 + pixels = np.full((Im_res, Re_res), complex(0,0))
  232 +
  233 + logger.info('Iterating z values')
  234 + for i in range(iters):
  235 +
  236 + prev_pixels = np.copy(pixels)
  237 + pixels = np.where(
  238 + np.logical_and(
  239 + pixels.real < 2.0, pixels.imag < 2.0
  240 + ),
  241 + brot(pixels, cdata),
  242 + pixels + complex(i,i)
  243 + )
  244 +
  245 + if np.array_equal(prev_pixels, pixels):
  246 + break
  247 +
  248 + logger.info('Rendering complete after %s iterations', i+1)
  249 + logger.info('Generating image data')
  250 +
212 ratio = 255 / iters 251 ratio = 255 / iters
213 - for Im in [Im_lim[1] + (Im_incr * y) for y in range(1, Im_res + 1)]:  
214 - for Re in [Re_lim[1] + (Re_incr * x) for x in range(1, Re_res + 1)]:  
215 -  
216 - c = complex(Re, Im)  
217 - z = complex(0,0)  
218 - count = 0  
219 -  
220 - for i in range(iters):  
221 - z = (z * z) + c  
222 - count += 1  
223 - if z.imag > 2.0 or z.real > 2.0:  
224 - break  
225 -  
226 - if count > iters:  
227 - app = 255  
228 - else:  
229 - app = int(255 * (count / iters)) 252 + img_data = np.zeros((Im_res, Re_res, 3), dtype=np.uint8)
230 253
231 - pixels.append([app, app, app])  
232 -  
233 - pixels = np.array(pixels, dtype=np.uint8)  
234 - pixels = pixels.reshape((Im_res, Re_res, 3)) 254 + for yidx, y in enumerate(pixels):
  255 + for xidx, x in enumerate(y):
  256 +
  257 + if x.real >= 2.0 or x.imag >= 2.0:
  258 + val = int((x.real / iters) * 255)
  259 + val = 1.0 if val > 1.0 else val
  260 + img_data[yidx][xidx] = [val] * 3
  261 + else:
  262 + img_data[yidx][xidx] = (255,255,255)
235 263
236 - logger.info('Writing image data to %s', args.outfile)  
237 - im = Image.fromarray(pixels) 264 + logger.info('Writing image to %s', args.outfile)
  265 + im = Image.fromarray(img_data)
238 im.save(args.outfile) 266 im.save(args.outfile)
239 267
240 end = time.time() 268 end = time.time()