有没有一种使用Python生成带渐变的位图的简单方法?

时间:2011-11-11 14:10:41

标签: python image matplotlib graphviz

我正在制作一个基于Python的简单程序,它将graphviz图作为输出。我想使用描述程序数据的自定义节点。一旦你有了图像,使用自定义节点很简单,但是我无法找到一种方便的方法来生成我想要的图像。

具体来说,我希望节点是圆形,其面积代表一个测量值,但其梯度代表该值的不确定性。使用由某些数学程序(例如sagemath)产生的等高线图似乎是合理的,但这些倾向于制作未缩放的方形图像。或者,图像处理程序上的梯度函数似乎很难与严格的高斯函数相关联。

理想情况下,我想按照这个伪代码的方式写一个函数......

def make_node_image(measured_value, std_dev):

    mean_circle_radius = sqrt(measured_value/pi)
    image_circle_radius = sqrt((measured_value + 2*std_dev)/pi)

    gradient_amplitude = 1/(std_dev*sqrt(2*pi))
    gradient_fade = e^(-(r-mean_circle_radius)^2/(2*std_dev^2))

    image_gradient = gradient_amplitude*gradient_fade

    ***generate_image_from_gradient***

    ***scale_and_clip_image_to_image_circle_radius***

    return image

两个星号是我需要帮助的地方;我很感激任何建议,谢谢!

1 个答案:

答案 0 :(得分:2)

实现此目的的一种方法是使用matplotlib,就像您在代码中所建议的那样。要做到这一点,我会

  1. 使用numpy创建一个NxN数组来表示image_gradient
  2. 创建一个figure,其形状为大小,单位为英寸,与圆的半径(image_circle_radius)相关,为此,您需要记住图中的点数。英寸(fig.dpi
  3. 创建一个没有边距,没有框架且没有刻度的axesfig.add_axes([0,0,1,1],frameon=False, xticks=[], yticks=[]
  4. 使用imshow将数组绘制为图像。
  5. 创建一个圆,中心和半径以DPI为单位
  6. 使用set_clip_path()方法剪切AxesImage调用创建的imshow
  7. 这种方法的灵感来自matplotlib example

    这是尝试做出规定的事情:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.path as path
    import matplotlib.patches as patches
    
    pi = np.pi
    sqrt = np.sqrt
    exp = np.exp
    
    def make_node_image(measured_value, std_dev, coverage="0.96",imageID=1):
    
        DPI = 100
        TODPI=1
        MINSIZE = 50 # in DPI
        MAXSIZE = 400 # in DPI
        MAXAMPLITUDE = .005
    
        # make radius,std_dev  values in grid units
        mean_circle_radius = int(sqrt(measured_value/pi)/TODPI)
        image_circle_radius = int(sqrt((measured_value + 2*std_dev)/pi)/TODPI)
        if image_circle_radius < MINSIZE:
            raise Exception("image_circle_radius too small!")
        if image_circle_radius > MAXSIZE:
            raise Exception("image_circle_radius too large!")
    
        grid_std_dev = std_dev/TODPI
    
        gradient_amplitude = 1/(std_dev*sqrt(2*pi))/MAXAMPLITUDE
        gradient_fade = np.zeros([2*image_circle_radius,
                                  2*image_circle_radius])
        for ix in range(2*image_circle_radius):
            for iy in range(2*image_circle_radius):
                r = sqrt((ix-image_circle_radius)**2
                         +(iy-image_circle_radius)**2)
                gradient_fade[ix,iy] = exp(
                    -(r-mean_circle_radius)**2
                     /(2*grid_std_dev**2))
    
        image_gradient = gradient_amplitude*gradient_fade
    
        fig = plt.figure(figsize=(2*image_circle_radius/DPI,
                                  2*image_circle_radius/DPI),dpi=DPI)
    
    
        ax = fig.add_axes([0,0,1,1],frameon=True, xticks=[], yticks=[])
    
        #***generate_image_from_gradient***
        im = ax.imshow(image_gradient,vmin=0,vmax=1)
    
        patch = patches.Circle((image_circle_radius,image_circle_radius), 
                               radius=image_circle_radius,fc='white')
    
        #***scale_and_clip_image_to_image_circle_radius***
        im.set_clip_path(patch)
    
        name = 'circImage%d.png'%imageID
        fig.savefig(name)
    
        return name
    
    make_node_image(90000*pi,100)
    

    这导致:

    enter image description here

    1. 圆圈似乎被夹在边缘。
    2. 几乎可以肯定的是构建gradient_fade的矢量化方法,虽然我手边还不知道它是什么。
    3. 这感觉很糟糕,我真的希望有人提供更优雅的答案。
    4. 显然上面的代码只是一个起点,有人可以肯定地改进它。