c++ - example - Crear un degradado lineal en una matriz 2D
graphics.h download (4)
Esta es realmente una cuestión matemática, por lo que podría ser discutible si realmente "pertenece" al desbordamiento de pila, pero de todos modos: debe proyectar las coordenadas de cada punto de la imagen en el eje de su gradiente y usar esa coordenada para determinar el color.
Matemáticamente, lo que quiero decir es:
- Digamos que su punto de partida es (x1, y1) y su punto final es (x2, y2)
- Calcule
A = (x2 - x1)
yB = (y2 - y1)
- Calcule
C1 = A * x1 + B * y1
para el punto inicial yC2 = A * x2 + B * y2
para el punto final (C2
debe ser mayor queC1
) - Para cada punto en la imagen, calcule
C = A * x + B * y
Si
C <= C1
, usa el color inicial; siC >= C2
, usa el color final; de lo contrario, use un promedio ponderado:(start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)
Hice algunas pruebas rápidas para comprobar que esto funcionó básicamente.
Tengo una matriz bidimensional similar a un mapa de bits, digamos 500 * 500 valores. Intento crear un degradado lineal en la matriz, por lo que el mapa de bits resultante se vería así (en escala de grises): Gradiente de ejemplo http://showandtell-graphics.com/images/gradient/gradient_12.jpg
La entrada sería la matriz a llenar, dos puntos (como el punto inicial y final de la herramienta Gradiente en Photoshop / GIMP) y el rango de valores que se usaría.
Mi mejor resultado actual es este:
texto alternativo http://img222.imageshack.us/img222/1733/gradientfe3.png
... que no está ni cerca de lo que me gustaría lograr. Se parece más a un gradiente radial.
¿Cuál es la forma más simple de crear dicho gradiente? Voy a implementarlo en C ++, pero me gustaría algún algoritmo general.
Voy a publicar mi solución.
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;
}
Para las aceleraciones, guarde en caché los valores de "dirección" derivados (sugerencia: premultiplicada por la revista).
En su imagen de ejemplo, parece que tiene un degradado radial. Aquí está mi explicación matemática imprompt para los pasos que necesitarás. Perdón por las matemáticas, las otras respuestas son mejores en términos de implementación.
- Defina una función lineal (como y = x + 1) con el dominio (es decir, x) del color con el que desea comenzar al color con el que desea finalizar. Puedes pensar en esto en términos de un rango dentro de Ox0 a OxFFFFFF (para color de 24 bits). Si quieres manejar cosas como el brillo, tendrás que hacer algunos trucos con el rango (es decir, el valor y).
- A continuación, debe asignar un vector a la matriz que tiene, ya que esto define la dirección en la que cambiarán los colores. Además, los valores de color definidos por su función lineal se asignarán en cada punto a lo largo del vector. El punto inicial y final del vector también define el mínimo y el máximo del dominio en 1. Puedes pensar en el vector como una línea de tu gradiente.
- Para cada celda de la matriz, a los colores se les puede asignar un valor del vector donde una línea perpendicular de la celda intersecta al vector. Vea el diagrama a continuación donde c es la posición de la celda y. es el punto de intersección. Si finges que el color en. es rojo, entonces eso es lo que asignarás a la celda.
| c | | Vect:____.______________ | |
Hay dos partes en este problema.
Dado dos colores A y B y un porcentaje de p, determine qué color se encuentra p ''por ciento del camino'' de A a B.
Dado un punto en un plano, encuentre la proyección ortogonal de ese punto en una línea determinada.
La línea dada en la parte 2 es tu línea de degradado. Dado cualquier punto P, proyectarlo en la línea de gradiente. Digamos que su proyección es R. Luego, determine qué tan lejos está R desde el punto de partida de su segmento de gradiente, como un porcentaje de la longitud del segmento de gradiente. Use este porcentaje en su función de la parte 1 anterior. Ese es el color P debería ser.
Tenga en cuenta que, al contrario de lo que otras personas han dicho, no puede simplemente ver sus colores como números regulares en su función de la parte 1. Eso seguramente no hará lo que quiera. Lo que haga depende del espacio de color que esté usando. Si quieres un degradado RGB, entonces tienes que mirar los componentes de color rojo, verde y azul por separado.
Por ejemplo, si quiere un color "a medio camino entre" rojo puro y azul, entonces en notación hexadecimal se trata de
ff 00 00
y
00 00 ff
Probablemente el color que quieres es algo así como
80 00 80
que es un lindo color morado Debe promediar cada componente de color por separado. Si intenta promediar los números hexadecimales 0xff0000 y 0x0000ff directamente, obtendrá 0x7F807F, que es un gris medio. Supongo que esto explica al menos parte del problema con su imagen de arriba.
Alternativamente, si se encuentra en el espacio de color HSV, quizás desee ajustar el componente de matiz solamente y dejar los otros tal como están.