在曼德尔布洛特集中实现平滑着色

问题描述 投票:0回答:1

我正在尝试使用 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')
python python-3.x fractals mandelbrot
1个回答
0
投票

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()
© www.soinside.com 2019 - 2024. All rights reserved.