我正在寻找一种通用算法来平滑地在两种颜色之间转换。
例如,此图片取自Wikipedia,并显示从橙色到蓝色的转换。
当我尝试使用我的代码(C ++)做同样的事情时,想到的第一个想法就是使用HSV色彩空间,但是显示出令人烦恼的中间颜色。
实现这一目标的好方法是什么?似乎与对比度的降低有关,或者可能使用不同的色彩空间?
答案 0 :(得分:14)
我过去做过很多这些。平滑可以通过许多不同的方式执行,但它们在这里可能采用的方式是简单的线性方法。这就是说,对于每个R,G和B分量,它们只是找出连接这两个点的“y = m * x + b”方程式,并用它来计算其间的分量。
m[RED] = (ColorRight[RED] - ColorLeft[RED]) / PixelsWidthAttemptingToFillIn
m[GREEN] = (ColorRight[GREEN] - ColorLeft[GREEN]) / PixelsWidthAttemptingToFillIn
m[BLUE] = (ColorRight[BLUE] - ColorLeft[BLUE]) / PixelsWidthAttemptingToFillIn
b[RED] = ColorLeft[RED]
b[GREEN] = ColorLeft[GREEN]
b[BLUE] = ColorLeft[BLUE]
现在之间有任何新颜色:
NewCol[pixelXFromLeft][RED] = m[RED] * pixelXFromLeft + ColorLeft[RED]
NewCol[pixelXFromLeft][GREEN] = m[GREEN] * pixelXFromLeft + ColorLeft[GREEN]
NewCol[pixelXFromLeft][BLUE] = m[BLUE] * pixelXFromLeft + ColorLeft[BLUE]
有许多数学方法可以创建转换,我们真正想要做的是了解您真正希望看到的转换。如果要查看上图中的确切过渡,则值得查看该图像的颜色值。我及时编写了一个程序来查看这些图像并以图形方式输出值。以下是上述伪彩色标度的程序输出。
基于查看图表,它比上面所述的线性更复杂。蓝色组件看起来大部分是线性的,红色可以模拟为线性,但绿色看起来更圆润。我们可以对绿色进行数学分析,以更好地理解它的数学函数,并使用它来代替。您可能会发现线性插值在0到70像素之间具有增加的斜率,在像素70之后具有线性递减斜率就足够了。
如果查看屏幕底部,此程序会给出每种颜色分量的一些统计测量值,例如最小值,最大值和平均值,以及图像读取的宽度像素数。
答案 1 :(得分:9)
R,G,B值的简单线性插值可以做到。
trumpetlicks has shown您使用的图像不是纯线性插值。但我认为插值可以为您提供所需的效果。下面我将在顶部显示线性插值,在底部显示原始图像。
这是产生它的(Python)代码:
for y in range(height/2):
for x in range(width):
p = x / float(width - 1)
r = int((1.0-p) * r1 + p * r2 + 0.5)
g = int((1.0-p) * g1 + p * g2 + 0.5)
b = int((1.0-p) * b1 + p * b2 + 0.5)
pix[x,y] = (r,g,b)
答案 2 :(得分:6)
HSV色彩空间不是用于平滑过渡的非常好的色彩空间。这是因为h
值hue仅用于在“色轮”周围任意定义不同的颜色。这意味着如果你在车轮上两种颜色之间走得很远,你将不得不穿过一堆其他颜色。一点也不顺利。
使用RGB(或CMYK)会更有意义。这些“组件”颜色空间更好地定义为平滑过渡,因为它们代表颜色需要的每个“组件”的数量。
每个组件值R,G和B的线性转换(参见@trumpetlicks答案)应该看起来“非常好”。任何超过“非常好”的东西都需要一个真正的人来调整这些值,因为我们的眼睛在不同颜色组中感知颜色值的差异和不对称性在RBG或CMYK(或任何标准)中都没有表示
维基百科图片使用的是Photoshop使用的算法。不幸的是,该算法尚未公开。
答案 3 :(得分:6)
我一直在研究如何根据调色板构建algorithm that takes a grayscale image as input and colorises it artificially:
输入■■■■■■■■与许多其他解决方案一样,该算法使用线性插值来进行颜色之间的转换。在您的示例中,应使用以下参数调用smooth_color_transition()
:
QImage input("gradient.jpg");
QVector<QColor> colors;
colors.push_back(QColor(242, 177, 103)); // orange
colors.push_back(QColor(124, 162, 248)); // blue-ish
QImage output = smooth_color_transition(input, colors);
output.save("output.jpg");
从算法中比较 原始图像 VS 输出 可以在下面看到:
输出中可以观察到的视觉假象已经存在于输入(灰度)中。当输入图像调整为189x51时,输入图像得到了这些假象。
这是使用更复杂的调色板创建的另一个示例:
输入■■■■■■■■
答案 4 :(得分:3)
对我来说似乎更容易使用RGB值创建渐变。您应该首先根据渐变的宽度计算每个值的颜色变化。对于R,G和B值,需要执行以下伪代码。
if (redValue1 == redValue2) {
redDifference = 0
} else {
redDifference = absoluteValue(redValue1 - redValue2) / widthOfGradient
}
if (redValue1 > redValue2) {
redDifference *= -1
}
然后,您可以使用这些值渲染每个像素,如下所示:
for (int i = 0; i < widthOfGradient; i++) {
int r = round(redValue1 + (i * redDifference))
// ...repeat for green and blue
drawLine(i, r, g, b)
}
我知道您指定使用的是C ++,但我创建了一个JSFiddle,演示了以第一个渐变为例:http://jsfiddle.net/eumf7/