从4个角点颜色插值的二维颜色渐变(256x256矩阵)

2024-03-29 14:56:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我想要实现的是以编程方式创建一个由256x256颜色值矩阵表示的二维颜色渐变。预期结果见附图。我的起点是矩阵的4个角点颜色,从中可以插值出中间剩余的254种颜色。虽然我在为一个轴插值颜色方面取得了一些成功,但是二维计算给我带来了一些令人头疼的问题。虽然图像似乎有一个非线性的颜色梯度,我会很高兴有一个线性的。在

如果您能给我一些提示,如何使用numpy或其他工具来实现这一点,我将不胜感激。在

enter image description here


Tags: 工具图像numpy颜色编程方式线性矩阵
3条回答

这是一个使用scipy.ndimage中的zoom function的超短解决方案。我用初始颜色(这里是随机的)定义一个2x2的RGB图像,并简单地将其缩放到256x256,order=1使插值线性化。代码如下:

import numpy as np
import matplotlib.pyplot as plt 

im=(np.random.rand(2,2,3)*255).astype(np.uint8)

from scipy.ndimage.interpolation import zoom
zoomed=zoom(im,(128,128,1),order=1)

plt.subplot(121)
plt.imshow(im,interpolation='nearest')
plt.subplot(122)
plt.imshow(zoomed,interpolation='nearest')
plt.show()

输出:

output from the script

这里有三种方法来做这个双线性插值。第一个版本用纯Python完成所有的算法,第二个版本使用PIL图像合成,第三个版本使用Numpy来完成算法。正如预期的那样,纯Python比其他方法慢得多。Numpy版本(源于Andras Deak编写的代码)几乎与小图像的PIL版本一样快,但是对于较大的图像,PIL版本明显更快。在

我也尝试在PIL中使用jadsq的缩放技术,但结果并不理想-我怀疑PIL的插值代码有点缺陷。在

如果您想创建大量相同大小的双线性渐变图像,PIL技术还有另一个优势:一旦您创建了构图遮罩,就不需要为每个图像重建它们。在

#!/usr/bin/env python3

''' Simple bilinear interpolation 
    Written by PM 2Ring 2016.09.14
'''

from PIL import Image
from math import floor
import numpy as np

def color_square0(colors, size):
    tl, tr, bl, br = colors
    m = size - 1
    r = range(size)

    def interp_2D(tl, tr, bl, br, x, y):
        u0, v0 = x / m, y / m
        u1, v1 = 1 - u0, 1 - v0
        return floor(0.5 + u1*v1*tl + u0*v1*tr + u1*v0*bl + u0*v0*br)

    data = bytes(interp_2D(tl[i], tr[i], bl[i], br[i], x, y)
        for y in r for x in r for i in (0, 1, 2))
    return Image.frombytes('RGB', (size, size), data)

# Fastest
def color_square1(colors, size):
    #Make an Image of each corner color
    tl, tr, bl, br = [Image.new('RGB', (size, size), color=c) for c in colors]

    #Make the composition mask
    mask = Image.new('L', (size, size))
    m = 255.0 / (size - 1)
    mask.putdata([int(m * x) for x in range(size)] * size) 

    imgt = Image.composite(tr, tl, mask)
    imgb = Image.composite(br, bl, mask)
    return Image.composite(imgb, imgt, mask.transpose(Image.TRANSPOSE))

# This function was derived from code written by Andras Deak    
def color_square2(colors, size):
    tl, tr, bl, br = map(np.array, colors)
    m = size - 1
    x, y = np.mgrid[0:size, 0:size]
    x = x[..., None] / m
    y = y[..., None] / m
    data = np.floor(x*y*br + (1-x)*y*tr + x*(1-y)*bl + (1-x)*(1-y)*tl + 0.5)
    return Image.fromarray(np.array(data, dtype = 'uint8'), 'RGB')

color_square = color_square1

#tl = (255, 0, 0)
#tr = (255, 255, 0)
#bl = (0, 0, 255)
#br = (0, 255, 0)

tl = (108, 115, 111)
tr = (239, 239, 192)
bl = (124, 137, 129)
br = (192, 192, 175)

colors = (tl, tr, bl, br)
size = 256
img = color_square(colors, size)
img.show()
#img.save('test.png')

输出

bilinear gradient


为了好玩,这里有一个使用Tkinter的简单GUI程序,可以用来生成这些渐变。在

^{pr2}$

这里有一个非常简单的方法来使用ImageMagick,它安装在大多数Linux发行版上,可用于OSX和Windows。还有Python绑定。不管怎样,只要在命令行中,在图像的4个角创建一个2x2的正方形,然后让ImageMagick展开并插值到全尺寸:

convert \( xc:"#59605c" xc:"#ebedb3" +append \) \
        \( xc:"#69766d" xc:"#b3b3a0" +append \) \
        -append -resize 256x256 result.png

enter image description here

第一行使左上角和右上角各一个1x1像素,并排附加两个。第二行为左下角和右下角各生成一个1x1像素,并排附加。最后一行将底行附加到顶行下方,并通过插值放大到256x256。在

如果您想更好地了解发生了什么,下面是相同的基本图像,但使用最近邻而不是插值进行缩放:

^{pr2}$

enter image description here

相关问题 更多 >