2016-11-28 19 views
1

Я создал фрактал Мандельброта, используя модуль PIL в Python. Теперь я хочу сделать GIF масштабирования в одну точку. Я смотрел другой код он-лайн, но, разумеется, я не понимал этого, так как шаблон, который я использую, немного отличается (я использую классы).Как сделать gif фрактального масштабирования mandelbrot (Python)?

Я знаю, что для увеличения я должен изменить масштаб ... Но я просто не знаю, как его реализовать.

from PIL import Image 
import random 


class Fractal: 
    """Fractal class.""" 

    def __init__(self, size, scale, computation): 
     """Constructor. 

     Arguments: 
     size -- the size of the image as a tuple (x, y) 
     scale -- the scale of x and y as a list of 2-tuple 
       [(minimum_x, minimum_y), (maximum_x, maximum_y)] 
     computation -- the function used for computing pixel values as a function 
     """ 
     self.size = size 
     self.scale = scale 
     self.computation = computation 
     self.img = Image.new("RGB", (size[0], size[1])) 

    def compute(self): 
     """ 
     Create the fractal by computing every pixel value. 
     """ 
     for y in range(self.size[1]): 
      for x in range(self.size[0]): 
       i = self.pixel_value((x, y)) 
       r = i % 8 * 32 
       g = i % 16 * 16 
       b = i % 32 * 8 
       self.img.putpixel((x, y), (r, g, b)) 

    def pixel_value(self, pixel): 
     """ 
     Return the number of iterations it took for the pixel to go out of bounds. 

     Arguments: 
     pixel -- the pixel coordinate (x, y) 

     Returns: 
     the number of iterations of computation it took to go out of bounds as integer. 
     """ 
     # x = pixel[0] * (self.scale[1][0] - self.scale[0][0])/self.size[0] + self.scale[0][0] 
     # y = pixel[1] * (self.scale[1][1] - self.scale[0][1])/self.size[1] + self.scale[0][1] 
     x = (pixel[0]/self.size[0]) * (self.scale[1][0] - self.scale[0][0]) + self.scale[0][0] 
     y = (pixel[1]/self.size[1]) * (self.scale[1][1] - self.scale[0][1]) + self.scale[0][1] 

     return self.computation((x, y)) 

    def save_image(self, filename): 
     """ 
     Save the image to hard drive. 

     Arguments: 
     filename -- the file name to save the file to as a string. 
     """ 
     self.img.save(filename, "PNG") 

if __name__ == "__main__": 
    def mandelbrot_computation(pixel): 
     """Return integer -> how many iterations it takes for the pixel to escape the mandelbrot set.""" 
     c = complex(pixel[0], pixel[1]) # Complex number: A + Bi (A is real number, B is imaginary number). 
     z = 0 # We are assuming the starting z value for each square is 0. 
     iterations = 0 # Will count how many iterations it takes for a pixel to escape the mandelbrot set. 

     for i in range(255): # The more iterations, the more detailed the mandelbrot set will be. 
      if abs(z) >= 2.0: # Checks, if pixel escapes the mandelbrot set. Same as square root of pix[0] and pix[1]. 
       break 
      z = z**2 + c 
      iterations += 1 

     return iterations 

    mandelbrot = Fractal((1000, 1000), [(-2, -2), (2, 2)], mandelbrot_computation()) 
    mandelbrot.compute() 
    mandelbrot.save_image("mandelbrot.png") 
+0

Добро пожаловать в StackOverflow. Прочтите и следуйте инструкциям по отправке в справочной документации. [Как спросить] (http://stackoverflow.com/help/how-to-ask) и [Минимальный, полный, проверяемый пример] (http://stackoverflow.com/help/mcve) применяются здесь. – Prune

+0

Привет и спасибо. Извините, я бросился с этим вопросом, так как Он так долго меня беспокоил. Спасибо за подробный ответ! –

+0

Мы здесь, чтобы помочь. Вы получите более качественные ответы, если будете придерживаться руководящих принципов публикации, что упростит чтение ускорителей. – Prune

ответ

1

Это «простая» линейная трансформация, как масштаб (масштабирование), так и перевод (сдвиг), как вы узнали в линейной алгебре. Вы помните формулу что-то вроде

s(y-k) = r(x-h) + c 

Перевод (h, k); масштаб в каждом направлении равен (r, s).

Чтобы реализовать это, вам нужно изменить свои приращения цикла. Чтобы увеличить масштаб в k в каждом направлении, вам необходимо уменьшить диапазон ваших координат, аналогично уменьшая приращение между положениями пикселей.

Самое главное здесь - частично отделить ваши отображаемые координаты от ваших математических значений: вы больше не показываете значение 0,2 - 0,5i в месте, помеченном (0,2, -0,5); новая позиция вычисляется из ваших новых фреймов.

Ваш старый код не совсем подходит для этого:

for y in range(self.size[1]): 
     for x in range(self.size[0]): 
      i = self.pixel_value((x, y)) 
      ... 
      self.img.putpixel((x, y), (r, g, b)) 

Вместо этого, вам нужно что-то вроде:

# Assume that the limits x_min, x_max, y_min, y_max 
    # are assigned by the zoom operation. 
    x_inc = (x_max - x_min)/self.size[0] 
    y_inc = (y_max - y_min)/self.size[1] 
    for y in range(self.size[1]): 
     for x in range(self.size[0]): 
      a = x*x_inc + x_min 
      b = y*y_inc + y_min 
      i = self.pixel_value((a, b)) 
      ... 
      self.img.putpixel((x, y), (r, g, b))