我正在尝试使用 HSV 值和 PIL 库为 MandelBrot 着色。
即使多次尝试摆弄HSV值,我也无法达到预期的效果。
这是我目前拥有的
这就是想要的效果
这是我正在尝试的代码,如果您可以添加一些提示来优化下面的代码以更快地计算集合,这也可能是有益的,我是 python 的新手
from PIL import Image
import random
import math
from decimal import Decimal
# Size of the Image Canvas
HEIGHT = 500
ZOOM = 0.0
Y_PAN = 0.0
# Range of the Complex Plane
MIN_X = -2.0 + ZOOM
MAX_X = 2.0 - ZOOM
MAX_Y = 2.0 + Y_PAN - ZOOM
MIN_Y = -2.0 + Y_PAN + ZOOM
DATA = []
def map_to_scale_d(x, in_min, in_max, out_min, out_max):
# returns float
return float((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
def map_to_scale(x, in_min, in_max, out_min, out_max):
# returns int
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
# Max iterations till Zn
ITER = 200
# loop to traverse every single point in Canvas
for y in xrange(HEIGHT):
for x in xrange(HEIGHT):
# convert to complex plane scale
a = map_to_scale_d(x, 0, HEIGHT, MIN_X, MAX_X)
b = map_to_scale_d(y, 0, HEIGHT, MAX_Y, MIN_Y)
# original values
_a = a
_b = b
counter = 0
# start the iteration at (a,b) in complex plane
# calculate z^2 + c
while(counter < ITER):
aa = a * a - b * b
bb = 2 * a * b
a = aa + _a
b = bb + _b
if((abs(aa + bb)) > 4):
break
counter = counter + 1
# initialise color
h = 0
s = map_to_scale(counter, 0, ITER, 0, 100)
v = map_to_scale(counter, 0, ITER, 0, 100)
if(counter == ITER):
h = 0
s = 0
v = 0
# convert to 8-bit
h = map_to_scale(h, 0, 360, 0, 255)
s = map_to_scale(s, 0, 100, 0, 255)
v = map_to_scale(v, 0, 100, 0, 255)
DATA.append((h, s, v))
img = Image.new('HSV', (HEIGHT, HEIGHT))
img.putdata(DATA)
img.show()
img.convert('RGB').save('test.png')
This 是一篇关于用 Python 绘制 Mandelbrot 集的精彩文章,非常详细地描述了该过程。按照他们的指示,您可以获得以下信息:
这是代码:
from dataclasses import dataclass
from math import log
from PIL import Image
import numpy as np
from scipy.interpolate import interp1d
@dataclass
class Viewport:
image: Image.Image
center: complex
width: float
@property
def height(self):
return self.scale * self.image.height
@property
def offset(self):
return self.center + complex(-self.width, self.height) / 2
@property
def scale(self):
return self.width / self.image.width
def __iter__(self):
for y in range(self.image.height):
for x in range(self.image.width):
yield Pixel(self, x, y)
@dataclass
class Pixel:
viewport: Viewport
x: int
y: int
@property
def color(self):
return self.viewport.image.getpixel((self.x, self.y))
@color.setter
def color(self, value):
self.viewport.image.putpixel((self.x, self.y), value)
def __complex__(self):
return (
complex(self.x, -self.y)
* self.viewport.scale
+ self.viewport.offset
)
@dataclass
class MandelbrotSet:
max_iterations: int
escape_radius: float = 2.0
def __contains__(self, c: complex):
return self.stability(c) == 1
def stability(self, c: complex, smooth=False, clamp=True):
value = self.escape_count(c, smooth) / self.max_iterations
return max(0.0, min(value, 1.0)) if clamp else value
def escape_count(self, c: complex, smooth=False):
z = 0
for iteration in range(self.max_iterations):
z = z ** 2 + c
if abs(z) > self.escape_radius:
if smooth:
return iteration + 1 - log(log(abs(z))) / log(2)
return iteration
return self.max_iterations
def paint(mandelbrot_set, viewport, palette, smooth):
for pixel in viewport:
stability = mandelbrot_set.stability(complex(pixel), smooth)
index = int(min(stability * len(palette), len(palette) - 1))
pixel.color = palette[index % len(palette)]
def denormalize(palette):
return [
tuple(int(channel * 255) for channel in color)
for color in palette
]
def make_gradient(colors, interpolation="linear"):
X = [i / (len(colors) - 1) for i in range(len(colors))]
Y = [[color[i] for color in colors] for i in range(3)]
channels = [interp1d(X, y, kind=interpolation) for y in Y]
return lambda x: [np.clip(channel(x), 0, 1) for channel in channels]
black = (0, 0, 0)
blue = (0, 0, 1)
brick = (0.9, 0.7, 0.4)
navy = (0, 0, 0.2)
red = (1, 0, 0)
light_gray = (0.9,0.9,0.9)
gray = (0.5, 0.5, 0.5)
num_colors = 1024
colors = [ navy, blue, light_gray, brick, gray, light_gray, black]
gradient = make_gradient(colors, interpolation="cubic")
palette = denormalize([
gradient(i / num_colors) for i in range(num_colors)
])
image = Image.new(mode="RGB", size=(800, 500))
mandelbrot_set = MandelbrotSet(max_iterations=35, escape_radius=1000)
viewport = Viewport(image, center=-0.75, width=3.75)
paint(mandelbrot_set, viewport, palette, smooth=True)
image.show()