如何在 python 中有效地创建重叠的半透明圆圈图像

How to efficiently create images of overlapping, semi-transparent circles in python

我正在私下研究一种遗传算法,该算法应该使用彩色圆圈来近似图片,类似于 this example written in javascript

该算法包含一个函数,可以根据个体的内部表示创建图片,用于计算其fitness,因此需要经常执行。

在下面找到一个最小的工作代码示例,它创建的图片完全符合我的要求,但是时间太长了:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
import numpy as np
from random import randint


class Circle:
    def __init__(self):
        self.position = (randint(0, 200), randint(0, 200))
        self.radius = randint(5, 50)
        self.color = self.to_hex(randint(0, 256**4))

    @staticmethod
    def to_hex(number, length=8):
        h = hex(number)[2:]
        while len(h) < length:
            h = "0" + h
        return h


def create_picture(circles, show=False):
    fig, ax = plt.subplots(figsize=(2, 2))
    plt.xlim(0, 200)
    plt.ylim(0, 200)
    plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
    plt.margins(0, 0)
    for c in circles:
        new = plt.Circle(c.position, c.radius, facecolor="#" + c.color, edgecolor=None)
        ax.add_patch(new)
    ax.axis('off')
    canvas = FigureCanvasAgg(fig)
    canvas.draw()
    width, height = fig.get_size_inches() * fig.get_dpi()
    img = np.frombuffer(canvas.tostring_rgb(), dtype='uint8').reshape(int(height), int(width), 3)
    if show:
        plt.show()
    plt.close(fig)
    return img

create_picture([Circle() for _ in range(100)], True)

我的问题是:如何以更有效的方式在 python(不一定是 matplotlib)中创建这样的图片?

我尝试过使用 PIL,但无法使透明度部分在那里工作。 我还尝试通过计算每个像素来计算 numpy 中的图片,这比我的 plt 解决方案还要慢。

如果有想法可以加快我的代码或替代方法,我会非常高兴。

试试 OpenCV。不幸的是,它不能开箱即用地绘制半透明圆圈,您必须先绘制一个圆圈,然后将结果与原始圆圈合并,这可能会减慢过程。但值得一试。

import cv2
import matplotlib.pyplot as plt
import numpy as np

def draw_circle(image, center, radius, color, alpha):
    overlay = image.copy()
    cv2.circle(image, center, radius, color, -1)
    cv2.addWeighted(image, alpha, overlay, 1 - alpha, 0, image)

im = np.zeros((200, 200, 3), np.uint8) + 255
draw_circle(im, (80, 80), 40, (255, 0, 0), 0.5)
draw_circle(im, (100, 100), 40, (0, 255, 0), 0.5)
draw_circle(im, (120, 120), 40, (0, 0, 255), 1/3)
plt.figure()
plt.imshow(im)
plt.show()