我有一个类似2D位图的数组,比方说500 * 500的值。我正在尝试在数组上创建线性渐变,因此生成的位图看起来像这样(灰度):
(来源:showandtell-graphics.com)
输入将是要填充的数组,两个点(如Photoshop / GIMP中渐变工具的起点和终点)以及将使用的值范围。
我目前最好的结果是:
alt text http://img222.imageshack.us/img222/1733/gradientfe3.png
......这远远不是我想要实现的目标。它看起来更像是径向渐变。
创建这样一个渐变的最简单方法是什么?我将用C ++实现它,但我想要一些通用的算法。
答案 0 :(得分:14)
这实际上是一个数学问题,所以它是否真的“属于”Stack Overflow可能是有争议的,但无论如何:你需要将图像中每个点的坐标投影到渐变的轴上并使用该坐标确定颜色。
数学上,我的意思是:
A = (x2 - x1)
和B = (y2 - y1)
C1 = A * x1 + B * y1
作为起点,C2 = A * x2 + B * y2
表示结束点(C2
应大于C1
)C = A * x + B * y
如果C <= C1
,请使用起始颜色;如果C >= C2
,请使用结束颜色;否则,使用加权平均值:
(start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)
我做了一些快速测试,检查这基本上是否有效。
答案 1 :(得分:3)
在示例图像中,看起来您有一个径向渐变。这是我对你需要的步骤的impromtu数学解释。对于数学,对不起,其他答案在实施方面更好。
| c | | Vect:____.______________ | |
答案 2 :(得分:1)
我会发布我的解决方案。
int ColourAt( int x, int y )
{
float imageX = (float)x / (float)BUFFER_WIDTH;
float imageY = (float)y / (float)BUFFER_WIDTH;
float xS = xStart / (float)BUFFER_WIDTH;
float yS = yStart / (float)BUFFER_WIDTH;
float xE = xEnd / (float)BUFFER_WIDTH;
float yE = yEnd / (float)BUFFER_WIDTH;
float xD = xE - xS;
float yD = yE - yS;
float mod = 1.0f / ( xD * xD + yD * yD );
float gradPos = ( ( imageX - xS ) * xD + ( imageY - yS ) * yD ) * mod;
float mag = gradPos > 0 ? gradPos < 1.0f ? gradPos : 1.0f : 0.0f;
int colour = (int)( 255 * mag );
colour |= ( colour << 16 ) + ( colour << 8 );
return colour;
}
对于加速,缓存派生的“方向”值(提示:由mag预乘)。
答案 3 :(得分:0)
这个问题有两个部分。
给定两种颜色A和B以及一些百分比p,确定从A到B的p'百分比是什么颜色。
给定平面上的一个点,找到该点在给定直线上的正交投影。
第2部分中的给定行是您的渐变线。给定任何点P,将其投影到梯度线上。假设它的投影是R.然后计算R距离渐变线段起点的距离,作为渐变线段长度的百分比。在上面第1部分的函数中使用此百分比。这就是P的颜色。
请注意,与其他人所说的相反,您不能只在第1部分的功能中将您的颜色视为常规数字。这几乎肯定不会达到您想要的效果。你做什么取决于你使用的色彩空间。如果您想要RGB渐变,则必须分别查看红色,绿色和蓝色组件。
例如,如果你想要一个颜色“中间的”纯红色和蓝色,那么你用的是十六进制表示法
ff 00 00
和
<00> 00 00 ff你想要的颜色可能就像
80 00 80
这是一种漂亮的紫色。您必须分别平均每个颜色组件。如果你试图直接平均十六进制数0xff0000和0x0000ff,你得到0x7F807F,这是一个中灰色。我猜这至少解释了上面你的照片的部分问题。
或者,如果您在HSV色彩空间中,您可能只想调整色调组件,并保留其他组件。