我正在寻找一种通用算法,能够使两种颜色之间实现平滑过渡。
例如,这张图片是从维基百科中获取的,显示了从橙色到蓝色的过渡。
当我尝试使用我的代码(C++)进行相同的操作时,首先想到的是使用HSV颜色空间,但是烦人的中间颜色会出现。
如何才能达到好的效果?似乎与对比度的减小或使用不同的颜色空间有关?
我正在寻找一种通用算法,能够使两种颜色之间实现平滑过渡。
例如,这张图片是从维基百科中获取的,显示了从橙色到蓝色的过渡。
当我尝试使用我的代码(C++)进行相同的操作时,首先想到的是使用HSV颜色空间,但是烦人的中间颜色会出现。
如何才能达到好的效果?似乎与对比度的减小或使用不同的颜色空间有关?
过去我已经做了很多这样的工作。平滑处理可以用许多不同的方法进行,但他们可能在这里采用的是一种简单的线性方法。换句话说,对于每个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像素后具有线性减少斜率是足够好的。
如果您查看屏幕底部,则此程序提供每个颜色分量的某些统计量(例如最小值、最大值和平均值)以及读取图像的像素宽度。
简单的线性插值R、G、B值就可以实现。
trumpetlicks表明,您使用的图像不是纯线性插值。但我认为,插值可以给您所需的效果。下面我展示了一个带有线性插值的图像和您原始图像在底部的图像。
以下是生成此图的(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)
r1
,r2
等是什么意思? - NullByte08我一直在研究如何构建一个算法,它以灰度图像为输入,并根据调色板进行人工着色:
■■■■ 灰度输入 ■■■■ 输出 ■■■■■■■■■■■■■■■
和其他许多解决方案一样,该算法使用线性插值来实现颜色之间的过渡。对于您的示例,应使用以下参数调用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");
可以观察到输出图像中的视觉伪影已经存在于输入(灰度)中。当将输入图像调整为189x51时,输入图像就出现了这些伪影。
这里有另一个使用更复杂的色彩调色板创建的示例:
■■■■ 灰度输入 ■■■■ 输出 ■■■■■■■■■■■■■■■
在我看来,使用RGB值创建渐变会更容易。您应该根据渐变的宽度首先计算每个值的颜色变化。以下伪代码需要针对R、G和B值执行。
redDifference = (redValue2 - redValue1) / widthOfGradient
然后,您可以使用这些值呈现每个像素,如下所示:
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/