Pregunta

figure

Dadas las coordenadas del píxel negro, podría interpolar los valores de las coordenadas del píxel azul mediante la ecuación matemática y = mx + c.Pero ¿qué pasa con los nuevos valores de píxeles RGB?¿Cómo puedo obtener el valor RGB promedio ponderado para los píxeles azules, dado que los valores RGB de los píxeles negros se dan como tales en la figura?

Cualquier ayuda es muy apreciada.Gracias de antemano.

¿Fue útil?

Solución

Interpolar los valores de forma independiente, realizando un cálculo cada uno para R, G y B. Por ejemplo, interpolando a mitad de camino entre (200,50,10) y (0,0,0) rendimientos (100,25,5).

Otros consejos

(Esto podría llevar mucho tiempo.Intentaré ser breve, en cuyo caso probablemente tendré que volver a mi respuesta para responder preguntas). La interpolación del espacio de color en RGB a menudo usa interpolación trilineal, que se puede construir sobre un par de interpolaciones bilineales.Pero no es necesario utilizar la interpolación trilineal.De hecho, otros interpoladores suelen ser mejores; por ejemplo, normalmente se prefiere un interpolante simple (o tetraédrico) al trilineal por diversas razones.Hay varias disecciones tetraédricas de una red que se pueden utilizar.Uno es bastante estándar.(No entraré en demasiados detalles allí, al menos no todavía.) Además, no hay ninguna razón por la que uno DEBE interpolar en RGB en lugar de algún otro espacio, aunque se podría argumentar que RGB tiene sus propios problemas especiales, generalmente alrededor de Interpolación de neutrales y casi neutrales.

La característica pertinente a RGB y a la interpolación es que un neutro se define como un punto tal que R=G=B.El interpolante trilineal tendrá un error máximo a lo largo de ese eje neutro y, por lo general, tendrá una forma característica (festoneada) para los errores a lo largo de la ruta neutra a través del espacio de color.

Entonces, ¿cómo interpolamos en 3-D?Supondré que se está interpolando en una red regular de puntos en el espacio de color.En ese caso, se puede identificar un cubo que contenga un solo punto.Si está interpolando dentro de un conjunto disperso de puntos, entonces la solución más simple suele ser construir una triangulación de esos puntos y luego hacer una interpolación simple (lineal) dentro de cualquier tetraedro dado.De todos modos, los interpoladores de orden superior son problemáticos aquí, ya que pueden causar problemas de color en algunas circunstancias.Por ejemplo, no desearíamos ver inversiones a lo largo de gradientes.Esto podría suceder ya que el timbre es un problema grave con los interpoladores basados ​​en splines en regiones con una curvatura relativamente alta.Y si hay un mapeo de gama involucrado, entonces tales transiciones seguramente serán un problema.Incluso si no se requiere un mapeo de gama, todavía quedan problemas de gama que abordar.

Hay varias formas de construir triangulaciones de dominios a partir de datos dispersos.Las formas alfa se basan en una triangulación de Delaunay y son una opción razonable.Pero suponiendo que tiene una red regular y desea realizar una interpolación trilineal, el problema se reduce a la interpolación dentro de un cubo simple en 3-d.

Tenga en cuenta que la interpolación trilineal no es verdaderamente una interpolación lineal, como tampoco lo es la interpolación bilineal.Estos esquemas son lineales SÓLO a lo largo de los ejes de la red, pero a lo largo de cualquier otro camino a través del espacio de color, tienen un carácter polinómico.Por lo tanto, un interpolante trilineal mostrará un comportamiento polinómico cúbico a lo largo de la diagonal principal o a lo largo de la mayoría de los caminos generales a través del cubo.Podemos convencernos de que la interpolación trilineal NO es verdaderamente lineal, ya que hay 8 puntos entre los que interpolamos.en 3-d, 4 puntos determinan una interpolante verdaderamente lineal, en función de esas variables independientes, pero tenemos 8 puntos que definen un cubo.Es decir, veremos un mapeo de un espacio RGB a otro como realmente 3 mapeos independientes, por lo tanto RGB --> UVW (he elegido UVW aquí para representar algún otro espacio de color genérico, que puede o no tener carácter RGB .)

El truco es que construimos un interpolante trilineal interpolando entre un par de interpoladores bilineales.Construimos esos interpoladores bilineales interpolando linealmente entre un par de puntos a lo largo de un borde y luego haciendo una tercera interpolación entre ellos.En realidad, podemos tratar un interpolante trilineal como si estuviera compuesto de 7 interpolaciones lineales simples.Curiosamente, se puede demostrar que no importa en qué ejes hagamos las interpolaciones primero.Por lo tanto, podemos interpolar primero a lo largo de los ejes R, luego B y luego G, o elegir cualquier otro orden: el interpolante trilineal será único e idéntico para cualquier orden elegido.(Lo mismo ocurre con el interpolante bilineal).

Entonces el truco es, ¿cómo hacemos una interpolación lineal entre dos tríadas de puntos?Primero, necesitamos determinar en qué parte del segmento de línea entre esos puntos nos encontramos.Por ejemplo, considere dos puntos en nuestro espacio de color que se encuentran a lo largo de un borde rojo (R) del cubo.Usaré los mismos valores que mostraste para esos puntos, así:

Q1 = [66, 51, 77]
Q2 = [55, 66, 77]

Estos son los valores entre los que interpolaremos, esencialmente la salida de nuestro mapeo, pero también necesitamos saber dónde se encuentran esos puntos en el espacio RGB de entrada.Entonces supongamos que estas coordenadas, basadas en las coordenadas del cubo del que provienen, son:

P1 = [0, 0, 0]
P2 = [1, 0, 0]

Este es un cubo unitario en 3-d tal como lo he escrito, por lo que los otros puntos estarían en

P3 = [0, 1, 0]
P4 = [1, 1, 0]
P5 = [0, 0, 1]
P6 = [1, 0, 1]
P7 = [0, 1, 1]
P8 = [1, 1, 1]

Por supuesto, cualquier cubo general también sirve y no hay razón para que sea un cubo verdadero.Cualquier prisma tridimensional recto, rectangular de 4 lados funcionará aquí también.Siempre puedes transformar cosas en el cubo unitario.

Ahora, supongamos que deseamos interpolar a lo largo de esta arista del cubo entre P1 y P2, en el dominio definido por Q1 y Q2.Elige algún punto a lo largo de ese borde.Puedes ver que solo R varía a lo largo de ese borde entre estos puntos, por lo que solo nos importa el valor de R en el punto en el que interpolamos.Piénselo en términos de un porcentaje de la distancia a lo largo del borde.La interpolación es simplemente un promedio ponderado de los dos puntos finales, una combinación lineal.Por lo tanto, para el punto con el valor rojo de r a lo largo del borde de 0 a 1 en el canal rojo, nuestra interpolación será

Q(r) = Q1*(1-r) + Q2*r

Como puede ver, cuando r es 1/2, es decir, a mitad del borde, nuestro interpolante se reducirá a

Q(1/2,0,0) = (Q1 + Q2)/2

Lógicamente, el valor del punto medio será la media de los dos puntos finales.La interpolación se realiza para CADA canal de salida de forma independiente.

Q(1/2,0,0) = ([66, 51, 77] + [55, 66, 77])/2 = [60.5, 58.5, 77]

¿Esto funciona para recuperar los puntos finales?Claro que lo hace.Cuando r = 0 o r = 1, puede ver que devuelve exactamente el Q1 o Q2 correspondiente.

Nuevamente, realiza esta interpolación a lo largo de cada uno de los cuatro bordes rojos para una interpolación trilineal.Luego haces DOS interpolaciones más, quizás a lo largo de los bordes verdes de los cuatro resultados que obtuvimos arriba.Finalmente, realiza una interpolación más a lo largo del borde azul para obtener la interpolación trilineal.Nuevamente, no importa en qué orden elijas los ejes de interpolación.El resultado será matemáticamente el mismo.

Si se detuviera en una interpolación bilineal, entonces hay tres de esas interpolaciones lineales.Sí, es cierto que una interpolación bilineal o una interpolación trilineal también se puede realizar como una combinación ponderada de las 4 (u 8) esquinas del rectángulo (o cubo).Eso puede dejarse para el futuro.

/*
  resize an image using bilinear interpolation
*/
void bilerp(unsigned char *dest, int dwidth, int dheight, unsigned char *src, int swidth, int sheight)
{
  float a, b;
  float red, green, blue, alpha;
  float dx, dy;
  float rx, ry;
  int x, y;
  int index0, index1, index2, index3;

  dx = ((float) swidth)/dwidth;
  dy = ((float) sheight)/dheight;
  for(y=0, ry = 0;y<dheight-1;y++, ry += dy)
  {
    b = ry - (int) ry;
    for(x=0, rx = 0;x<dwidth-1;x++, rx += dx)
    {
      a = rx - (int) rx;
      index0 = (int)ry * swidth + (int) rx;
      index1 = index0 + 1;
      index2 = index0 + swidth;     
      index3 = index0 + swidth + 1;

      red = src[index0*4] * (1.0f-a)*(1.0f-b);
      green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
      blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
      alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
      red += src[index1*4] * (a)*(1.0f-b);
      green += src[index1*4+1] * (a)*(1.0f-b);
      blue += src[index1*4+2] * (a)*(1.0f-b);
      alpha += src[index1*4+3] * (a)*(1.0f-b);
      red += src[index2*4] * (1.0f-a)*(b);
      green += src[index2*4+1] * (1.0f-a)*(b);
      blue += src[index2*4+2] * (1.0f-a)*(b);
      alpha += src[index2*4+3] * (1.0f-a)*(b);
      red += src[index3*4] * (a)*(b);
      green += src[index3*4+1] * (a)*(b);
      blue += src[index3*4+2] * (a)*(b);
      alpha += src[index3*4+3] * (a)*(b);

      red = red < 0 ? 0 : red > 255 ? 255 : red;
      green = green < 0 ? 0 : green > 255 ? 255 : green;
      blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
      alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;

      dest[(y*dwidth+x)*4] = (unsigned char) red;
      dest[(y*dwidth+x)*4+1] = (unsigned char) green;
      dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
      dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
    }
    index0 = (int)ry * swidth + (int) rx;
    index1 = index0;
    index2 = index0 + swidth;     
    index3 = index0 + swidth;   

    red = src[index0*4] * (1.0f-a)*(1.0f-b);
    green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
    blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
    alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
    red += src[index1*4] * (a)*(1.0f-b);
    green += src[index1*4+1] * (a)*(1.0f-b);
    blue += src[index1*4+2] * (a)*(1.0f-b);
    alpha += src[index1*4+3] * (a)*(1.0f-b);
    red += src[index2*4] * (1.0f-a)*(b);
    green += src[index2*4+1] * (1.0f-a)*(b);
    blue += src[index2*4+2] * (1.0f-a)*(b);
    alpha += src[index2*4+3] * (1.0f-a)*(b);
    red += src[index3*4] * (a)*(b);
    green += src[index3*4+1] * (a)*(b);
    blue += src[index3*4+2] * (a)*(b);
    alpha += src[index3*4+3] * (a)*(b);

    red = red < 0 ? 0 : red > 255 ? 255 : red;
    green = green < 0 ? 0 : green > 255 ? 255 : green;
    blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
    alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;

    dest[(y*dwidth+x)*4] = (unsigned char) red;
    dest[(y*dwidth+x)*4+1] = (unsigned char) green;
    dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
    dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
  }
  index0 = (int)ry * swidth + (int) rx;
  index1 = index0;
  index2 = index0 + swidth;     
  index3 = index0 + swidth;   

  for(x=0, rx = 0;x<dwidth-1;x++, rx += dx)
  {
    a = rx - (int) rx;
    index0 = (int)ry * swidth + (int) rx;
    index1 = index0 + 1;
    index2 = index0;     
    index3 = index0;

    red = src[index0*4] * (1.0f-a)*(1.0f-b);
    green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
    blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
    alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
    red += src[index1*4] * (a)*(1.0f-b);
    green += src[index1*4+1] * (a)*(1.0f-b);
    blue += src[index1*4+2] * (a)*(1.0f-b);
    alpha += src[index1*4+3] * (a)*(1.0f-b);
    red += src[index2*4] * (1.0f-a)*(b);
    green += src[index2*4+1] * (1.0f-a)*(b);
    blue += src[index2*4+2] * (1.0f-a)*(b);
    alpha += src[index2*4+3] * (1.0f-a)*(b);
    red += src[index3*4] * (a)*(b);
    green += src[index3*4+1] * (a)*(b);
    blue += src[index3*4+2] * (a)*(b);
    alpha += src[index3*4+3] * (a)*(b);

    red = red < 0 ? 0 : red > 255 ? 255 : red;
    green = green < 0 ? 0 : green > 255 ? 255 : green;
    blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
    alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;

    dest[(y*dwidth+x)*4] = (unsigned char) red;
    dest[(y*dwidth+x)*4+1] = (unsigned char) green;
    dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
    dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
  }

   dest[(y*dwidth+x)*4] = src[((sheight-1)*swidth+swidth-1)*4];
   dest[(y*dwidth+x)*4+1] = src[((sheight-1)*swidth+swidth-1)*4+1];
   dest[(y*dwidth+x)*4+2] = src[((sheight-1)*swidth+swidth-1)*4+2];
   dest[(y*dwidth+x)*4+3] = src[((sheight-1)*swidth+swidth-1)*4+3];
}  

Código mantenido aquí

https://github.com/malcolmmclean/babyxrc/blob/master/src/resize.c

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top