miércoles, 23 de mayo de 2012

Resumen


Procesamiento de imágenes
El procesamiento digital de imágenes se distinguen dos niveles principales de manera general:

Procesamiento de imágenes a bajo nivel

Muy poco uso de conocimiento respecto al contenido de las imágenes.
Secuencia de cuatro para el procesamiento a bajo nivel: adquisición de la imagen, pre-procesamiento, segmentación de la imagen, descripción y clasificación de objetos.

Entendimiento de imágenes alto nivel
Existe la capacidad de realizar toma de decisiones respecto al contenido de las imágenes.
Las herramientas para adquisición de imágenes, transforman la imagen visual de un objeto físico y sus características intrínsecas en un conjunto de datos digitalizados
Las herramientas para la adquisición de imágenes transforman la imagen visual de un objeto físico y sus características intrínsecas en un conjunto de datos digitalizados, usados para procesarla.

El procesamiento digital de imágenes tiene diversas aplicaciones y problemas:
·         Representación
·         Transformación
·         Modelado
·         Restauración
·         Reconstrucción
·         Análisis
·         Comprensión de datos

Filtros para la eliminación de ruido en las imágenes
Existen filtros para la eliminación de ruido en imágenes, Esto se detecta en un electrocardiograma como los cuadros que aparecen en el fondo de la imagene, asi como un pixel. Por eso se desarrollaron algoritmo parala restauracion de imagenes.


Filtro gaussiano

Este filtro tienen el inconveniente de que, además de remover el ruido, empana la imagen ocasionando perdida de los detalles mas finos. Es comúnmente utilizado en aplicaciones de detección de bordes y análisis de escala espacial.

Filtro de suavizado direccional (preservación de bordes)

La eliminación de ruido mediante suavizado distorsiona la información con respecto a los bordes. Para reducir el empañamiento de bordes al realizar el suavizado se puede usar un filtro de promediado direccional que se calcula en varias direcciones.

Filtro de suavizado conservador

Esta técnica de reducción del nivel de ruido emplea un algoritmo de filtración simple y rápido que sacrifica su poder de eliminación de ruido a cambio de preservar el detalle espacial de la frecuencia en una imagen, removiendo píxeles aislados con un valor muy alto o muy bajo.

Realce de contraste

Tiene como objetivo mejorar la calidad de las imágenes bajo ciertos criterios subjetivos del ojo humano. Normalmente esta técnica es utilizada como una etapa de pre-procesamiento para sistemas de reconocimiento de patrones.

Filtro paso bajo

Es un tipo de filtro de suavizado empleado para remover ruido de alta frecuencia espacial en una imagen digital. Este ruido es generalmente introducido en la imagen durante el proceso de conversión de analógico a digital como un efecto secundario de la conversión física de patrones de energía luminosa a patrones eléctricos.Se lleva a cabo mediante una cancelación de las variaciones más rápidas entre píxel y píxel. El ruido aparece de manera aleatoria a manera de puntos en la imagen, usualmente con valores bastante distintos a los vecinos más cercanos.

Filtro paso alto

Opera de la misma manera que el filtro paso bajo, mediante el análisis de los valores de cada píxel y cambiando estos de acuerdo a los valores de los píxeles vecinos. El efecto en este filtro es, sin embargo, el opuesto. En vez de obtener un suavizado de la imagen, el filtro paso alto realza detalles de la imagen. El uso de este filtro debe reservarse preferentemente a imágenes con muy poco ruido.

Filtro SUSAN (Smallest Univalue Segment Assimilating Nucleus) 

Este algoritmo es para la eliminación de ruido preserva la estructura de la imagen alisando únicamente sobre los píxeles que se encuentran dentro de la región del pixel analizado (pixel central) tomando un excedente del promedio de los pixeles en la localidad que cae dentro del USAN (Univalue Segment Assimilating Nucleus).

Operaciones para la detección de errores

La detección de esquinas y líneas se basa en los operadores de detección de bordes, mismo que mediante el cálculo de primeras y segundas derivadas permiten determinar puntos de principal importancia para poder realizar las mediciones necesarias.
Al hablar de detección de bordes, el termino sugiere que la aplicación de un algoritmo con este propósito dará como resultado un contorno.

Animación por computadora

La animación es la simulación de un movimiento, creada por una serie de imágenes o cuadros. La animación por computadora se puede definir como un formato de presentación de información digital en movimiento a través de una secuencia de imágenes o cuadros creadas o generadas por la computadora.

Animación Basada en Cuadros

Para hacer una secuencia, se van filmando las imágenes cuadro por cuadro y luego estos se unen para formar la animación. Es posible formar bibliotecas de movimientos de cada parte del cuerpo de la animación para de esta forma combinarlas y hacer animaciones diferentes.

Animación Basada en Sprites

Se refiere a animaciones de objetos sobre fondos estáticos, es decir, lo que cambia son los personajes.

Key Framming

Se refiere a establecer posiciones en puntos específicos de tiempo en una animación y la parte intermedia la obtiene la computadora por medio de interpolación matemática.

Rotoscopiado

Se obtienen la posición y el ángulo de los puntos clave de imágenes reales y se trata de hacer converger los modelos en computadora con ellos.

Motion Control

Consiste en obtener posiciones clave de manera automática a partir de un actor real por medio de dispositivos que se conectan a su cuerpo.

Wavelets

Significa “pequeñas ondulaciones”. Esta técnica permite que en una sola imagen se compriman una gran cantidad de datos para que al acercarse a ella, se vayan viendo los detalles.

Técnicas de Pixar

El proceso que utiliza Pixar para crear sus animaciones se compone de cuatro etapas principales: Desarrollo (crear el guión de la historia), preproducción (se direccionan los retos técnicos), producción (creación de la película) y post producción (pulir los últimos detalles).

Muñeco de jengibre

viernes, 18 de mayo de 2012

Usos de la graficación

Medicina



La Informática Gráfica está jugando un papel cada vez más importante en campos como la diagnosis médica y cirugía. A través de imágenes el médico diagnostica enfermedades y el cirujano es capaz de realizar intervenciones quirúrgicas con menores riesgos. Usando aparato de ultra sonido para ver el desarrollo fetal, resonancias magnéticas para ver la composición de los órganos en su interior.


Educación


Donde se están introduciendo los métodos multimedia e hipertexto para mejorar las actitudes hacia el aprendizaje de los alumnos de edades tempranas.


A menudo, se utilizan como instrumentos de ayuda educativa modelos de sistemas físicos, financieros y económicos, los cuales se generan por computadora. Modelos de sistemas físicos, fisiológicos, tendencias de población, pueden ayudar a los estudiantes a comprender la operación del sistema.


En el caso de algunas aplicaciones de capacitación, se diseñan sistemas especiales. Como ejemplos de tales sistemas especializados, podemos mencionar los simuladores para sesiones de práctica o capacitación de capitanes de barco, pilotos de avión, operadores de equipo pesado y el personal de control de tráfico aéreo.


Publicidad


Una imagen dice mas de mil palabras. Para la publicidad siempre funciona por medio de una buena marca, política o un emblema que lo diferencie.


Si un puesto o lugar no tiene una atractivo para el cliente este no es apreciado. Para la gente lo mas nuevo o con aires de novedad les llama la atención. La graficación permite desarrollar una buena imagen en 3D o inclusive un comercial para la propaganda de cualquier negocio. Hay que irse innovando ya que todo va evolucionando de una manera exponencial y hay que tenerse todo al margen.


Entretenimiento


En la actualidad, se utilizan comúnmente métodos de gráficas por computadora para producir películas, videos musicales y programas de televisión. En ocasiones se despliegan solo imágenes gráficas y otras veces se combinan objetos (creados en la computadora) con actores u objetos reales.


Fuentes consultadas


http://www.infor.uva.es/~descuder/docencia/pd/node111.html

viernes, 4 de mayo de 2012

Unidad IV. Iluminación y sombreado


4.1 Relleno de polígonos
Color de relleno
Para elegir el color de los polígonos, basta con hacer una llamada a glColor entre la definición de cada polígono. Por ejemplo, modificando el código que dibujaba dos triángulos:
glBegin(GL_TRIANGLES);
      glColor3f(1.0f, 0.0f, 0.0f);
      glVertex3f(0.0f,0.0f, 0.0f);
      glVertex3f(2.0f,0.0f, 0.0f);
      glVertex3f(1.0f,1.0f, 0.0f);

      glColor3f(0.0f,1.0f, 0.0f);
      glVertex3f(-1.0f,0.0f, 0.0f);
      glVertex3f(-3.0f,2.0f, 0.0f);
      glVertex3f(-2.0f,0.0f, 0.0f);
glEnd();
Esta modificación provocará que el primer triángulo se pinte en rojo y el segundo en verde. La función glColor define el color de rellenado actual y lleva como parámetros los valores de las componentes RGB del color deseado y, opcionalmente, un cuarto parámetro con el valor alpha. Estos parámetros son flotantes y se mueven en el rango [0.0,1.0]. Con ello se pueden componer todos los colores del modo de video usado en ese instante.

Rellenos de Polígonos en OpenGL.
Es el método que utiliza OpenGL para rellenar de color los polígonos. Se especifica con la función glShadeModel. Si el parámetro es GL_FLAT, ogl rellenará los polígonos con el color activo en el momento que se definió el último parámetro; si es GL_SMOOTH, ogl rellenará el polígono interpolando los colores activos en la definición de cada vértice.
Este código es un ejemplo de GL_FLAT:

glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLES);  
      glColor3f(1.0f, 0.0f, 0.0f);  // activamos el color rojo
      glVertex3f(-1.0f, 0.0f, 0.0f);
      glColor3f(0.0f, 1.0f, 0.0f);  // activamos el color verde
      glVertex3f(1.0f, 0.0f, 0.0f);
      glColor3f(0.0f, 0.0f, 1.0f);  // activamos el color azul
      glVertex3f(0.0f, 1.0f, 0.0f);
glEnd();

Técnicas de sombreado clásicas y avanzadas
Clásicas: iluminación local

Cálculos de iluminación por vértices
Para aplicar iluminación a un objeto necesitamos asociar un vector normal a cada vértice del objeto.  Cuando tenemos la normal calculada tenemos que normalizarla, o sea, dividir ese vector por su propio modulo para que sea unitario, pero también podemos hacer que se encargue la OpengGl activando la normalización con el comando glEnable GL_NORMALIZE o desactivarla con glDisable GL_NORMALIZE.
El usar GL_NORMALIZE dependerá de nuestra aplicación ya que si forzamos a que sea OpenGl el que las utilice se ralentiza por que le estamos obligando a hacer mas cálculos de los que debe.
Para definir las normales en opengl utilizaremos la función glNormal3f(X,Y,Z) por ejemplo para definir una cara con 4 vértices la definiremos de la siguiente manera:
GlBegin GL_QUADS
glNormal3f nX,nY,nZ
glvertex3f x,y,z
glvertex3f x,y,z
glvertex3f x,y,z
glvertex3f x,y,z
glEnd

Renderizado en Tiempo real
La idea fundamental del procesado en tiempo real es que todos los objetos deben ser descompuestos en polígonos. Estos polígonos serán descompuestos a su vez en triángulos. Cada triángulo será proyectado sobre la ventana bidimensional y rellenado con los colores adecuados para reflejar los efectos de la iluminación, texturas, etc. Una vez se han generado los triángulos, en la pipeline existen dos partes claramente diferenciadas: una primera etapa operaciones realizadas sobre cada uno de los vértices, y después de que éstos se proyecten sobre la ventana, entonces comienza una segunda fase de cálculos realizados para cada pixel cubierto por triángulos.

Iluminación global
              Considera la luz reflejada por un punto teniendo en cuenta toda la luz que llega
              No solo procedente de las luces
              Efectos
             producen sombras
             reflexión de un objeto en los otros
             transparencias

Trazado de Rayos
El trazado de rayos computa la interacción de la luz desde un punto de vista determinado y es particularmente adecuado para superficies reflectantes. Puede utilizarse como propiedad específica de un determinado material.

Radiosidad
Está basado en principios generales que se pueden encontrar en un manual general sobre rendering. En el estadio inicial la escena consta de dos tipos de objetos: objetos que emiten luz y objetos que reciben luz. A partir de aquí, en una primera vuelta, se computa la luz que recibe cada objeto o, en una aproximación más exacta, cada parte de un objeto, según una subdivisión cuya densidad puede precisarse en sucesivas aproximaciones.

Cálculos de iluminación por pixel
La iluminación por píxel en tiempo real es una tecnología revolucionaria ofrecida como primicia por NVIDIA Shading Rasterizer. La iluminación dinámica a nivel de píxel libera a los desarrolladores de las restricciones de otros sistemas de iluminación y pone a su alcance toda una gama de sofisticados efectos. Antes de que el color final del píxel sea decidido, un cálculo de iluminación debe ser computado para sombrear a los píxeles basados en alguna luz que puede estar presente en la escena.

Alto Acabado
Sombreado Constante o plano. Un cálculo para todo el polígono. Obtenemos una intensidad  que aplicamos a un conjunto de puntos de un objeto (p.ej. todo un triángulo). Aceleramos el proceso de síntesis.  Correcto si se verifica: Fuente de luz en el infinito. Observador en el infinito. El polígono representa una superficie plana real del objeto que se modela y no es una aproximación de un objeto curvo.

Sombreado Constante o Plano
 Obtenemos una intensidad que aplicamos a un conjunto de puntos de un objeto
  *Aceleramos el proceso de síntesis
  *Correcto si se verifica.
  * Fuente de luz en el infinito
  *Observador en el infinito

Sombreado de Gouraud
• Es un  método todo incremental que una interpolación de intensidades.
• En cada vértice del polígono se calcula la intensidad. La intensidad de los puntos intermedios se calcula por interpolación bilineal.
Cálculo
 11 Calcular intensidad en los vértices
 1.1. Calcular normal en el vértice: para evitar visualizar las aristas la normal se calcula como la las aristas, la normal se calcula como la media de las normales de polígonos adyacentes.
1.2. Calcular la intensidad del vértice Iv  según el modelo de iluminación de Phong
2. Calcular la intensidad de los puntos interiores p p por interpolación lineal de las de los vértices.

Sombreado de Phong
• Es un método todo incremental que realiza una interpolación de normales (en vez de   interpolación de intensidades).
• En cada vértice del polígono se calcula la normal como media de las normales de los polígonos adyacentes. La normal de los adyacentes. La normal de los puntos intermedios se calcula por  interpolación lineal.
• En cada punto se aplica el modelo de iluminación de Phong.
Cálculo
• 1 Calcular normal en los vértices
– Como en el sombreado de Gouraud, para evitar visualizar las aristas, la normal se calcula como la media de las normales de los polígonos adyacentes.
• 2. Calcular la normal de los puntos interiores por interpolación lineal de las de los vértices.
• 3. Calculo de la intensidad:
– Calcularla en cada punto mediante el modelo de iluminación de Phong.
– Ahora se puede introducir también la reflexión especular

Ray Tracing
En muchas formas, ray tracing es una extensión al enfoque de rendering con un modelo de iluminación local. Está basado en la observación previa que, de los rayos de luz saliendo de una fuente, los únicos que contribuyen a la imagen son aquellos que entran al lente de la cámara sintética y pasan por el centro de proyección.

Buffer Stencil.
Stencill Buffer es una memoria intermedia que analiza y actualiza píxeles (con sus operaciones) junto con “depth buffer” o buffer de profundidad. Añade planos de bits adicionales para cada píxel además de los bits de color y profundidad.
 Stencil buffer es similar al buffer de profundidad en que los dos son colección de planos de bit que no se pueden mostrar. Del mismo modo que el buffer de profundidad asocia a cada píxel de la ventana un valor de profundidad, el stencil buffer asocia su propio valor a cada píxel mostrado. Cuando el buffer de profundidad esta activado los valores de profundidad son usados para aceptar o rechazar fragmentos, del mismo modo los valores de Stencil buffer son usados para aceptar o rechazar fragmentos.

Buffer de Acumulación
Normalmente se usa un buffer de acumulación para unir  dos imágenes

Fuentes de Luz
La luz puede dejar una superficie mediante dos procesos fundamentales:
              Emisión propia
              Reflexión
 Normalmente se piensa en una fuente de luz como un objeto que emite luz solo mediante fuentes de energía internas, sin embargo, una fuente de luz, como un foco, puede reflejar alguna luz incidente a esta del ambiente.

 Fuentes de Luz
La luz puede dejar una superficie mediante dos procesos fundamentales:
·         Emisión propia
·         Reflexión

Luz Ambiente
La luz ambiente ilumina por igual todas las zonas en sombra para simular el efecto de interacción entre objetos que hace que las partes en sombra de los objetos queden parcialmente iluminadas.

Spotlights (direccionales)
Los spotlights se caracterizan por un rango delgado de ángulos por los cuales se emite luz. Se puede construir un spotlight sencillo de una fuente de punto limitando los ángulos de donde la luz de la fuente se puede ver. Se puede usar un cono cuyo ápice está en ps, apuntando en la dirección ls, y cuyo ancho está determinado por el ángulo θ.
Fuentes:
http://cannes.itam.mx/Alfredo/Espaniol/Cursos/Grafica/Sombreado.pdf
http://dac.escet.urjc.es/docencia/IG/08-IluminacionSombreado4.pdf
http://sabia.tic.udc.es/gc/Tutorial%20OpenGL/tutorial/cap3.htm


martes, 17 de abril de 2012

Funciones para graficar círculos y elipses


Ecuación Ordinaria de la Circunferencia

Dados las coordenadas del centro de la circunferencia C(h;k) y el radio "r" de la misma, podemos utilizar la siguiente ecuación para determinar el valor de "y" correspondiente a un valor de "x".

Ejemplo:

Hallar la ecuación de la circunferencia cuyo centro es C(2;6) y con radio r = 4

(x - 2)² + (y - 6)² = 4²

Ecuación Canónica de la Circunferencia

Sean ahora las coordenadas del centro de la circunferencia C(0;0) y el radio "r", podemos utilizar la siguiente ecuación para determinar el valor de "y" correspondiente a un valor de "x".

Ejemplo:

Hallar la ecuación de la circunferencia cuyo centro es el origen y con radio r = 3

x ² + y ² = 3²



Forma cartesiana centrada en origen
La ecuación de una elipse en coordenadas cartesianas, con centro en el origen, es:
donde a > 0 y b > 0 son los semiejes de la elipse, donde si a corresponde al eje de las abscisas y b al eje de las ordenadas la elipse es horizontal, si es al revés, entonces es vertical. El origen O es la mitad del segmento [FF']. La distancia entre los focos FF' se llama distancia focal y vale 2c = 2ea, siendo e la excentricidad y a el semieje mayor.
Forma cartesiana centrada fuera del origen
Si el centro de la elipse se encuentra en el punto (h,k), la ecuación es:
Forma polar centrada en origen
En coordenadas polares, con origen en su centro, la ecuación de la elipse es:

Formas polares centradas en un foco



En coordenadas polares, con el origen en uno de sus focos, la ecuación de la elipse es:
REFERENCIAS:

lunes, 16 de abril de 2012

gluLookAt()

La función gluLookAt() en Open gl nos sirve para observar un objeto como si lo viéramos por una cámara que capta las imágenes.
Permite definir de forma específica donde se va a situar la cámara, hacía donde mirará ésta y cuál será el orden de los ejes de coordenadas.

gluLookAt(eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ)

Las primeras tres coordenadas es en que punto en el espacio se ubicara la cámara, las siguientes tres coordenadas es hacia que punto mirara la cámara y las ultimas tres es un vector en que tanto estará elevada la cámara para enfocar el punto al que se mira.

glTranslatef y GlutAt() se comportan de la misma manera en cuestion de que el objeto se puede ver como nosotros lo deseemos en un punto especifico la diferencia esta que en glTranslatef el obejto es movido, las coordenadas originales son modificadas, cambia su ubicacion en el espacio, mientras que en GlutAt() el objeto no es movido del espacio sino el angulo o forma en que se visualiza ese objeto por el lente de la "camara", lo que hace que se comporten de manera similar.


Ejecucion de codigo

domingo, 15 de abril de 2012

Carro con movimiento

#include
GLfloat anguloCuboX = 0.0f;
GLfloat anguloCuboY = 0.0f;
GLfloat anguloEsfera = 0.0f;
GLfloat TrasPisox=0.0f;
GLfloat TrasPisoy=0.0f;
GLfloat TrasPisoz=-5.0f;

GLfloat TrasRueda1x=3.0f;
GLfloat TrasRueda1y=0.5f;
GLfloat TrasRueda1z=-1.0f;

GLfloat TrasRueda2x=-0.5f;
GLfloat TrasRueda2y=0.5f;
GLfloat TrasRueda2z=-1.0f;

GLfloat TrasCarrox=0.0f;
GLfloat TrasCarroy=0.0f;
GLfloat TrasCarroz=-5.0f;

GLfloat e;
GLint ancho=400;
GLint alto=400;
int hazPerspectiva = 0;
void reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if(hazPerspectiva)
               gluPerspective(60.0f, (GLfloat)width/(GLfloat)height, 1.0f, 20.0f);
     else
       glOrtho(-4,4, -4, 4, 1, 10);
       glMatrixMode(GL_MODELVIEW);
    ancho = width;
    alto = height;
}
void Piso(void)
{
    glColor3f(0.0f, 0.0f, 1.0f);
    glScalef(1.5f,0.0f,1.5f);
    glBegin(GL_QUADS);       //cara abajo
    glVertex3f( 1.0f,-1.0f, -1.0f);
    glVertex3f( 1.0f,-1.0f,  1.0f);
    glVertex3f(-1.0f,-1.0f,  1.0f);
    glVertex3f(-1.0f,-1.0f, -1.0f);
    glEnd();
}
void carro(void)
{
    glColor3f(1.0f, 0.0f, 1.0f);

    glBegin(GL_POLYGON);       //carro
    glVertex3f(-1.5f,0.5f, -2.0f);
    glVertex3f( 3.5f,0.5f, -2.0f);
    glVertex3f(3.5f,2.0f,  -2.0f);
    glVertex3f(2.0f,2.0f, -2.0f);
    glVertex3f(1.f,3.0f, -2.0f);
    glVertex3f(-0.5f,3.0f, -2.0f);
    glVertex3f(-1.5f,2.0f, -2.0f);
    glEnd();
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
glTranslatef(TrasPisox,TrasPisoy,TrasPisoz);
    glRotatef(15, 1.0f, 0.0f, 0.0f);
    glRotatef(15, 0.0f, 1.0f, 0.0f);
    // dibuja piso
    Piso();
 
// dibuja rueda
    glLoadIdentity();
    glTranslatef(TrasRueda1x,TrasRueda1y,TrasRueda1z);
    glColor3f(1.0f, 1.0f, 1.0f);
    glutSolidSphere(0.5f, 16, 16);
 
//dibuja 2da rueda
    glLoadIdentity();
    glTranslatef(TrasRueda2x,TrasRueda2y,TrasRueda2z);
    glColor3f(1.0f, 1.0f, 1.0f);
    glutSolidSphere(0.5f, 16, 16);


    glLoadIdentity();
    glTranslatef(TrasCarrox,TrasCarroy,TrasCarroz);
    glColor3f(1.0f, 1.0f, 1.0f);
    carro();
    glFlush();
    glutSwapBuffers();
}
void init()
{
    glClearColor(0,0,0,0);
    glEnable(GL_DEPTH_TEST);
    ancho = 400;
    alto = 400;
}
void idle()
{
    display();
}


void keyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
    case 'p':
    case 'P':
 hazPerspectiva=1;
 reshape(ancho,alto);
 break;
    case 'o':
    case 'O':
 hazPerspectiva=0;
 reshape(ancho,alto);
 break;
    case 'i':
    case 'I':

   TrasRueda1x-=.10;
   TrasRueda2x-=.10;
   TrasCarrox-=.10;

 break;

case 'd':
    case 'D':
    TrasRueda1x+=.10;
TrasRueda2x+=.10;
    TrasCarrox+=.10;

      break;
    }
}



int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(ancho, alto);
    glutCreateWindow("Carrito");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}