You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用cmath优化Python分形渲染后出现黑色边框问题求助

曼德博集合渲染:解决优化后的黑边问题

我编写了一个曼德博集合渲染程序,优化后渲染时长从40秒缩短到12秒,但迭代次数增加的区域出现了黑色边框。问题出在使用cmaths.isinf()判断发散的逻辑上——部分已经发散的点还未达到inf状态,被误判为属于集合(渲染为黑色)。以下是问题详情和解决方案:

完整原代码

from PIL import Image
from PIL import ImageShow
from PIL import ImageColor as ImageColour
import cmath as cmaths

colours = [
    "navy", "darkblue", "blue", "cornflowerblue", "lightsteelblue",
    "lightskyblue", "turquoise", "palegreen", "lawngreen", "greenyellow",
    "yellowgreen", "goldenrod", "gold", "yellow", "darkorange",
    "orange", "brown", "maroon", "red", "deeppink", "darkmagenta",
    "mediumorchid", "magenta", "darkviolet", "slateblue",
]


def testpoint(c, zoom):
    zofn = 0.0
    count = 0
    while not cmaths.isinf(zofn) and count < (5 * zoom):
        zofn = (zofn * zofn) + c
        count = count + 1
    if str(zofn)[1] != "n":
        return -1
    else:
        return count


def mainprogram():
    zoom = zoom = int(input("Set Zoom Level. (Default: 10)     ") or "10") * 10
    centre_x = int(input("Input centre x value. (Default: -50)     ") or "-50")
    centre_y = int(input("Input centre y value. (Default: 0)     ") or "0")
    halfw = result.width // 2
    halfh = result.height // 2
    for i in range((centre_y - halfh), (centre_y + halfh)):
        for x in range((centre_x - halfw), (centre_x + halfw)):
            coordinate = complex((x / zoom), (i / zoom))
            value = testpoint(coordinate, zoom)
            if value == -1:
                colour = (0, 0, 0)
            else:
                colour = ImageColour.getrgb(colours[value % len(colours)])
            result.putpixel(
                ((x + halfw) % result.width, (i + halfh) % result.height), colour
            )
        print("line", (i + 250), "done")
    ImageShow.show(result)
    mainprogram()


result = Image.new("RGB", (1000, 500), "Black")
mainprogram()

代码差异对比

  • 原判断逻辑(无黑边但速度慢):
    while str(zofn)[1] != "n" and count < (5*zoom):
    
  • 优化后逻辑(速度快但有黑边):
    while not cmaths.isinf(zofn) and count < (5*zoom):
    

解决方案

方案1:遵循数学定义判断发散(最优)

根据曼德博集合的数学规则:若复数z的模大于2,则该点必然发散。直接判断模的平方(避免开根号,提升速度)是否超过4,比isinf()更准确且高效。

修改后的testpoint函数:

def testpoint(c, zoom):
    z_real = 0.0
    z_imag = 0.0
    count = 0
    max_iter = 5 * zoom
    while (z_real ** 2 + z_imag ** 2) <= 4 and count < max_iter:
        # 拆分复数运算为实部虚部计算,减少开销
        new_real = z_real ** 2 - z_imag ** 2 + c.real
        new_imag = 2 * z_real * z_imag + c.imag
        z_real, z_imag = new_real, new_imag
        count += 1
    # 达到最大迭代次数则视为在集合内(黑色),否则返回迭代次数
    return -1 if count == max_iter else count

额外优化点:

  • 修正mainprogram中重复的zoom = zoom = ...赋值,改为zoom = int(input(...) or "10") * 10
  • 移除putpixel中的取模操作(x和y的范围不会超出图像尺寸):
    result.putpixel((x + halfw, i + halfh), colour)
    

方案2:修复isinf()的漏判问题

如果坚持使用isinf(),可以在循环结束后补充判断模是否大于2,避免漏判发散点:

def testpoint(c, zoom):
    zofn = 0.0
    count = 0
    max_iter = 5 * zoom
    while not cmaths.isinf(zofn) and count < max_iter:
        zofn = zofn ** 2 + c
        count += 1
    # 补充判断:模大于2也视为发散
    if cmaths.isinf(zofn) or abs(zofn) > 2:
        return count
    else:
        return -1

此方案性能略逊于方案1,因为复数运算和模计算的开销更高。

内容的提问来源于stack exchange,提问作者Jessica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 08:44:56