Python - 用X,Y位置定义RGB值创建颜色映射表

3
我正在解决一个问题,但只解决了其中一半。我正在处理带有X,Y坐标的2D绘图空间。我想在绘图空间上设置4个点,并为每个点设置颜色并生成颜色映射。
我能够使用2个点生成颜色映射-创建向量并从一个点到另一个点。然而,这种方法在几何意义上创建了覆盖点的2D平面/1D线。但是如果设置4个点,则需要生成表面。换句话说,我需要在这些点之间适配表面。
以下是我的想象示意图: 这是我用于生成从一个X,Y,[RGB]到另一个X,Y,[RGB]的直接变化的代码。
import numpy as np 
import colorsys
import cv2

a = np.array([100,0,0]) # Point one with x=0,y=0-max and rgb value
b =  np.array([0,255,0]) # point two with x=max,y=0-max and rgb value
#in this case i loop from y=0 to y=max for corresponding point on the other side of drawing space - that is x=max
a = a[::-1]
b= b[::-1]
leds = 31 # just constant
h_color=100 # height of drawing space
t_lengt = (600/leds)*leds #recalculation of width (because I need integer)
vector = (b-a)*1.0/t_lengt

arr_texture = np.zeros(shape=[h_color, t_lengt, 3], dtype=np.uint8) #drawing space defined by x,y and 3d value

for i in range(t_lengt): # loop for all points in x=0 to x=max (that is y=0 to max)
    for j in range(h_color):

        arr_texture[j][i]=[a[0]+vector[0]*i,a[1]+vector[1]*i,a[2]+vector[2]*i]


cv2.imwrite('color_img.jpg', arr_texture)
cv2.imshow("image", arr_texture);
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

我对这种方法感到非常困惑,因为绘图空间上的点由X、Y坐标定义,但它们携带[R、G、B]值。

总之,我需要将3个以上的点拟合到创建色彩地图表面中,其中这些点具有X、Y坐标,但携带[R、G、B]值。

提前致谢。


你能告诉我们你从代码角度尝试了什么吗? - Rishikesh Jha
这个问题中没有 [tag:python]。 - Peter Wood
我还没有尝试过除了在两个x,y点之间进行RGB值的颜色映射(但这不是我需要的内容)以外的任何事情。我无法编写代码,因为我甚至不知道如何做到这一点。如果我有x,y,z值,我可以做到,但我不知道z维度是否包含RGB形式的3D值。但好吧,我会添加我所拥有但不需要的代码。 - Martin
你需要做三次相同的操作...分别对R、G、B进行插值,然后将结果放入单个颜色中...这是3倍双线性插值,因此需要进行3*3线性插值...请查看我在你其他问题中提供的链接。 - Spektre
1个回答

1
你知道每个角落的RGB值,所以要创建一张颜色地图,你只需要一个函数,它将接受一个坐标(x,y)(其中x和y在0到1的范围内),并返回该坐标处的RGB值。
为此,我们需要实现双线性插值bilinear interpolation,这是线性插值到二维插值的扩展。
你可以通过在顶部两个角之间进行插值,然后将此结果与底部两个角之间的插值结果相结合来执行双线性插值。
a ----|---- b
      |
      |
c ----|-----d

在编写我们的主要函数之前,我们需要一个辅助函数来执行插值,因为我们将使用它九次。

这可以是线性的:

def lerp(x, a, b):
    return a + x * (b-a)

或者使用更加平滑的函数,比如smoothstep函数:

def serp(x, a, b):
    return a + (3*x**2 - 2*x**3) * (b-a)

(原来在这种情况下,我们只是去角落(而不是像使用Perlin噪声生成器时那样去山丘),线性产生了更渐进的渐变!)
该函数将以四个长度为3的列表/ numpy数组(abcd)和坐标(xy)作为输入,返回该坐标处的RGB值。请保留HTML标签。
def get_color(x, y, a, b, c, d):
    r = lerp(y, lerp(x, a[0], b[0]), lerp(x, c[0], d[0]))
    g = lerp(y, lerp(x, a[1], b[1]), lerp(x, c[1], d[1]))
    b = lerp(y, lerp(x, a[2], b[2]), lerp(x, c[2], d[2]))
    return np.array([r, g, b])

或者,我们可以使用列表推导式使其更符合Python风格:
def get_color(x, y, a, b, c, d):
    return np.array([lerp(y, lerp(x, a[i], b[i]),
                             lerp(x, c[i], d[i])) for i in range(3)])

现在我们只需要在一个numpy数组上进行评估,我们可以使用np.meshgrid(有关替代方法,请参见此问题)。
哦,我将使用matplotlib进行绘图,因为我没有安装OpenCV
import matplotlib.pyplot as plt
import numpy as np
w = h = 200
verts = [[255,0,0],[0,255,0],[0,0,255],[255,0,0]]
img = np.empty((h,w,3), np.uint8)
for y in range(h):
    for x in range(w):
        img[y,x] = get_color(x/w, y/h, *verts)
plt.imshow(img)
plt.show()

它会显示以下图像:

colormap.jpg


这种技术也被用于柏林噪声中,使我能够创建这个地形生成器

谢谢,我已经解决了这个问题。但是当你引入5种或更多颜色时,它并不是非常有用。双线性插值对此来说太简单了。我尝试使用b. inter.来处理多种颜色,但结果很糟糕。我甚至尝试了三角剖分,其中三角形边缘是双线性inter.的边缘,但结果很丑陋。在三角形内部进行b.插值也不能得到平滑的结果。我相信真正的解决方案是一种算法,类似于Kohen Maps,每种颜色之间存在影响力的斗争 - 也就是分类的一种方式。 - Martin
@Martin,您能否添加一个期望结果的示例,其中包含5种颜色。谢谢。 - Joe Iddon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接