Línea suavizada | Algoritmo de Xiaolin Wu

Dibujo de línea suavizada A
continuación se muestra la imagen que muestra la línea dibujada con el algoritmo de línea de Bresenham (izquierda) y el algoritmo de línea de Xiaolin Wu (derecha) que suaviza la línea. ¿Cuál te parece mejor? Concepto de Anti Aliasing Supongamos que queremos dibujar una línea desde el punto (1, 1) al punto (8, 4) con bordes rectangulares. La línea ideal sería la que se muestra en la figura A. Como quiero mostrarlo en la pantalla, no puedo usar eso. La línea debe pasar por un proceso llamado Rasterización que determinaría el color de los píxeles individuales. Se pueden usar varios algoritmos como el algoritmo de línea de Bresenham , el analizador diferencial digital , el algoritmo de línea de Xiaolin Wu, el algoritmo de Gupta-Sproull. Más tarde, dos realizan anti-aliasing o suavizado de líneas.
AALine


El resultado producido por los dos primeros algoritmos se muestra en la figura B.
solidfill
firstrast

Hay pocos problemas en Línea (figura B).
1. Pixel (4,2) tiene menos cobertura que Pixel (3,2), pero ambos están dibujados completamente en negro.
2. El píxel (2,2) tiene casi tanta cobertura como (4,2) y, sin embargo, se dibuja completamente en blanco.
Para superar estos inconvenientes y producir una línea mucho más suave, usamos el algoritmo de línea de Xiaolin Wu.

Algoritmo de línea de Xiaolin Wu
Considere la figura que se muestra a continuación, que se dibuja utilizando el Algoritmo de generación de línea de Bresenham. Tome un segmento y su coordenada inicial x. Por la X en el bucle se suma 1 hacia el final del segmento. En cada paso, se calcula el error: la distancia entre la coordenada y real en esa ubicación y la celda de cuadrícula más cercana. Si el error no supera la mitad de la altura de la celda, se rellena. Ese es todo el algoritmo. Modificaremos este algoritmo para que pueda producir una línea suavizada.
original-a04cf694-556504fba7413

El algoritmo de línea de Xiaolin Wu se caracteriza por el hecho de que en cada paso del cálculo se realiza para los dos más cercanos a la línea de píxeles, y se colorean con diferente intensidad, dependiendo de la distancia. La intensidad del píxel central de la intersección actual da el 100% si el píxel está dentro de los 0,9 píxeles, la intensidad será del 10%. En otras palabras, el cien por cien de la intensidad se divide entre los píxeles que limitan la línea del vector en ambos lados. En la imagen, el color rojo y verde muestra la distancia a los dos píxeles adyacentes. Para calcular el error, puede usar el punto flotante y tomar el valor del error de la parte fraccionaria.
original-ccf57794-556504fc0787f

NOTA: La siguiente implementación usa la biblioteca SDL para dibujar píxeles en la pantalla. Si está en un sistema Debian como ubuntu, simplemente ejecute el siguiente comando para instalar la biblioteca SDL.

sudo apt-get install libsdl2-dev

Para construir uso

gcc filename.c -lSDL2

Nota: si la proyección del segmento en el eje x es menor que la proyección en el eje y, o si se intercambian el principio y el final del segmento, el algoritmo no funcionará. Para evitar esto, debe verificar la dirección del vector y su pendiente, y luego intercambiar las coordenadas de la línea, en última instancia, para reducir todo a uno o al menos dos casos.
El siguiente algoritmo asume que solo se proporcionarán coordenadas enteras como entradas, ya que el valor del píxel no puede ser un punto flotante.

// C program to implement Xiaolin Wu's line drawing
// algorithm.
// We must install SDL library using above steps
// to run this program
#include<SDL2/SDL.h>
  
// SDL stuff
SDL_Window* pWindow = 0;
SDL_Renderer* pRenderer = 0;
  
// swaps two numbers
void swap(int* a , int*b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
  
// returns absolute value of number
float absolute(float x )
{
    if (x < 0) return -x;
    else return x;
}
  
//returns integer part of a floating point number
int iPartOfNumber(float x)
{
    return (int)x;
}
  
//rounds off a number
int roundNumber(float x)
{
    return iPartOfNumber(x + 0.5) ;
}
  
//returns fractional part of a number
float fPartOfNumber(float x)
{
    if (x>0) return x - iPartOfNumber(x);
    else return x - (iPartOfNumber(x)+1);
  
}
  
//returns 1 - fractional part of number
float rfPartOfNumber(float x)
{
    return 1 - fPartOfNumber(x);
}
  
// draws a pixel on screen of given brightness
// 0<=brightness<=1. We can use your own library
// to draw on screen
void drawPixel( int x , int y , float brightness)
{
    int c = 255*brightness;
    SDL_SetRenderDrawColor(pRenderer, c, c, c, 255);
    SDL_RenderDrawPoint(pRenderer, x, y);
}
  
void drawAALine(int x0 , int y0 , int x1 , int y1)
{
    int steep = absolute(y1 - y0) > absolute(x1 - x0) ;
  
    // swap the co-ordinates if slope > 1 or we
    // draw backwards
    if (steep)
    {
        swap(&x0 , &y0);
        swap(&x1 , &y1);
    }
    if (x0 > x1)
    {
        swap(&x0 ,&x1);
        swap(&y0 ,&y1);
    }
  
    //compute the slope
    float dx = x1-x0;
    float dy = y1-y0;
    float gradient = dy/dx;
    if (dx == 0.0)
        gradient = 1;
  
    int xpxl1 = x0;
    int xpxl2 = x1;
    float intersectY = y0;
  
    // main loop
    if (steep)
    {
        int x;
        for (x = xpxl1 ; x <=xpxl2 ; x++)
        {
            // pixel coverage is determined by fractional
            // part of y co-ordinate
            drawPixel(iPartOfNumber(intersectY), x,
                        rfPartOfNumber(intersectY));
            drawPixel(iPartOfNumber(intersectY)-1, x,
                        fPartOfNumber(intersectY));
            intersectY += gradient;
        }
    }
    else
    {
        int x;
        for (x = xpxl1 ; x <=xpxl2 ; x++)
        {
            // pixel coverage is determined by fractional
            // part of y co-ordinate
            drawPixel(x, iPartOfNumber(intersectY),
                        rfPartOfNumber(intersectY));
            drawPixel(x, iPartOfNumber(intersectY)-1,
                          fPartOfNumber(intersectY));
            intersectY += gradient;
        }
    }
  
}
  
// Driver code
int main(int argc, char* args[])
{
  
    SDL_Event event;
  
    // initialize SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) >= 0)
    {
        // if succeeded create our window
        pWindow = SDL_CreateWindow("Anti-Aliased Line ",
                     SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                                          640, 480,
                                                  SDL_WINDOW_SHOWN);
  
        // if the window creation succeeded create our renderer
        if (pWindow != 0)
            pRenderer = SDL_CreateRenderer(pWindow, -1, 0);
    }
    else
        return 1; // sdl could not initialize
  
    while (1)
    {
        if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
            break;
  
        // Sets background color to white
        SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
        SDL_RenderClear(pRenderer);
  
        // draws a black AALine
        drawAALine(80 , 200 , 550, 150);
  
        // show the window
        SDL_RenderPresent(pRenderer);
    }
  
    // clean up SDL
    SDL_Quit();
    return 0;
}

Producción:

outputAALine

Referencias:
https://courses.engr.illinois.edu/ece390/archive/archive-f2000/mp/mp4/anti.html
https://unionassets.com/blog/algorithm-brezenhema-and-wu-s-line -299
https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
Este artículo es una contribución de Lokesh Sharma . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *