c++ 平滑颜色过渡算法

nzk0hqpo  于 2022-12-05  发布在  其他
关注(0)|答案(5)|浏览(218)

我正在寻找一个通用的算法,以顺利过渡两种颜色。
例如,此图像取自Wikipedia,显示了从橙子到蓝色的过渡。

当我尝试使用我的代码(C++)做同样的事情时,我首先想到的是使用HSV颜色空间,但是恼人的中间颜色出现了。

实现这一点的好方法是什么?似乎与对比度的降低有关,或者可能使用不同的颜色空间?

au9on6nz

au9on6nz1#

我以前做过很多这样的事情。平滑可以用很多不同的方法来完成,但是他们在这里做的可能是一个简单的线性方法。也就是说,对于每个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像素之后斜率线性减少的线性插值已经足够好了。
如果你看屏幕的底部,这个程序会给出每个颜色分量的一些统计度量,比如最小值、最大值和平均值,以及所读图像的像素宽度。

vuktfyat

vuktfyat2#

一个简单的线性插值的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)
vm0i2vca

vm0i2vca3#

HSV颜色空间并不是一个很好的用于平滑过渡的颜色空间。这是因为h值hue只是用来任意定义“色轮”周围的不同颜色。这意味着如果你在色轮上相距很远的两种颜色之间移动,你将不得不穿过一堆其他颜色。一点也不平滑。
使用RGB(或CMYK)会更有意义。这些“组件”颜色空间更适合进行平滑过渡,因为它们表示一种颜色需要多少每个“组件”。
每个分量值的线性过渡(见@trumpetlicks答案),R、G和B应该看起来“相当不错”。任何超过“相当不错”的值都需要实际的人来调整值,因为我们的眼睛在不同的颜色组中感知颜色值的方式存在差异和不对称性,这些颜色组不是以RBG或CMYK(或任何标准)表示的。
维基百科图片使用的是Photoshop使用的算法。不幸的是,该算法并不公开。

laawzig2

laawzig24#

我已经对此进行了研究,根据调色板构建了一个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时出现这些伪影。
下面是使用更复杂的调色板创建的另一个示例:

■■■■灰阶输入■■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■

第一次

dgjrabp2

dgjrabp25#

在我看来,使用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/

相关问题