Issuu on Google+

060-064_VTK_PythonLinux6

20.04.2005

14:09 Uhr

Página 60

DESARROLLO • Python

Visualización 3D con VTK (Visualization Toolkit)

GRÁFICAS 3D

Hoy por hoy, la representación gráfica 3D y su visualización forman parte de nuestra vida cotidiana; basta fijarse en el mundo del entretenimiento, en la industria del juego y en el soporte de hardware y software para tales fines. ¿Quién en su ordenador personal no ha instalado un juego, visto una película, renderizada en 3D? POR ANA M. FERREIRO FERREIRO Y JOSÉ A. GARCÍA RODRÍGUEZ

L

a representación gráfica en 3D ofrece la posibilidad de crear mundos virtuales en un ordenador, lo cual unido a la visualización permite al usuario explorar y entender, rápidamente, sistemas complicados. Esto es posible gracias al avance de lenguajes orientados a objetos, que ofrecen la posibilidad de crear software de mejor calidad y más fácil de mantener. Entre las diferentes herramientas de visualización, representación 3D y procesamiento de imágenes, cabe destacar VTK (Visualization Toolkit), código abierto cuyo núcleo está implementado en C++ y que soporta envolturas (“wrappers”) para TCL, Python y Java; permitiendo el desarrollo de aplicaciones complejas de un modo eficiente y mediante scripts sencillos. Por todo ello, VTK se emplea en la visualización médica, la visualización industrial, reconstrucción de superficies a partir de digitalización láser o nubes de puntos desorganizados, etc. En lo que sigue veremos los conceptos básicos en los que se basa VTK para poder generar una escena y, mediante

60

Número 06

una serie de ejemplos, desarrollados en Python, llegaremos a crear nuestras propias escenas de visualización.

Instalación Para poder realizar todas las pruebas que se van sugiriendo y las que se os ocurran, es necesario tener instalado Python y VTK con soporte para Python. Además la tarjeta gráfica de nuestro ordenador debe tener OpenGL funcionando. Hay dos maneras de conseguir instalar VTK: la primera es descargar los binarios para nuestro sistema. En el caso de SuSE, Red Hat (Fedora) ó Mandrake nos bastará con buscar los siguientes paquetes rpm, por ejemplo para Mandrake 10.1: vtk-4.2.2-5mdk.i586.rpm vtk-python4.2.2-5mdk.i586.rpm vtk-tcl-4.2.25mdk.i586.rpm vtk-examples-4.2.25mdk.i586.rpm vtk-devel-4.2.25mdk.i586.rpm Estos paquetes los podemos bajar, por ejemplo para Mandrake 10.1, desde RedIris en [1]: La otra manera es instalarlo a partir del código fuente,que se explica en el Cuadro 1.

WWW.LINUX- MAGAZINE.ES

Modelos de Objetos VTK Para los inexpertos en el mundo de la visualización, vamos a explicar de un modo sencillo la estructura de VTK; porque esto permite que comprendamos mejor cada uno de los pasos que iremos realizando. Por un momento, imaginad que estáis en la butaca del cine, viendo una película de animación, como por ejemplo “La Edad de Hielo”. Si nos centramos en una única escena y la describimos, vemos personajes animados (actores), luces de diferentes tonalidades, cámaras que modifican el punto de vista, propiedades de los personajes (color, forma, etc.). Aunque no lo creáis todos estos conceptos son la base de la visualización gráfica. Veamos dicha estructura. El toolkit de visualización VTK está diseñado a partir de dos modelos claramente diferenciables: el modelo gráfico y el modelo de visualización. • Modelo gráfico. El modelo gráfico captura las principales características de un sistema gráfico 3D, de un modo fácil de entender y usar (ver Figura 1).


060-064_VTK_PythonLinux6

20.04.2005

14:10 Uhr

Página 61

Python • DESARROLLO

Figura 1: Estructura del modelo gráfico.

La abstracción se basa en la industria del cine. Los objetos básicos que constituyen este modelo son: vtkRenderer, vtkRenderWindow, vtkLight, vtkCamera, vtkProp, vtkProperty, vtkMapper, vtkTransform. En la Tabla 1 se describen cada uno de estos objetos. • Modelo de visualización. El papel del modelo gráfico es transformar datos gráficos en imágenes, mientras que el papel de modelo de visualización transforma información en datos gráficos; esto significa que el modelo de visualización es el responsable de construir la representación geométrica que se renderiza mediante el modelo gráfico. VTK se basa en la aproximación de los datos para transformar la información en datos gráficos. Hay dos tipos básicos de objetos, descritos en la Tabla 2, involucrados en dicha aproximación: vtkDataObject y vtkProcessObject. Los diferentes tipos de datos que pueden constituir un objetos son, entre otros, puntos, rectas, polígonos, puntos estructurados, mallas estructuradas y no estructuradas, etc. (ver Figura 2).

Mi Primera Escena Ya estamos preparados para construir nuestra primera escena. Situaros en el papel de director de cine. En los siguientes ejemplos veremos el modo de emplear las clases que acabamos de describir. Para ello, tal como se menciona al comienzo, instanciaremos VTK desde Python.

Figura 2: Tipos de datos: a) datos poligonales, b) puntos estructurados c) malla no estructurada d) malla estructurada.

mediante el método SetRenderWindow. En este momento no se aprecia la utilidad del mismo, paciencia… ya comprenderéis su importancia cuando tengamos un actor en nuestra escena. Guardamos el fichero y import vtk en la línea de comandos ejecutamos el programa, Ahora que ya podemos tecleando python cone.py… instanciar cualquier objeto ¡No ocurre nada! Esto es de VTK, sin más que porque debemos inicializar escribir vtk.nombre_clase, la interacción del usuario e necesitamos crear nuestra indicar que la ventana de ventana de renderizado renderizado permanezca vtk.vtkRenderWindow, a la Figura 3: Ventana de renvisible hasta que el usuario que llamaremos renWin y derizado por defecto. finalice la ejecución de la a la que asociamos un área misma cerrándola. Para ello basta de renderizado vtk.vtkRenderer (que escribir denominamos ren), mediante el método AddRenderer(). Escribamos las siguientes líneas de código: iren.Initialize() Con cualquier editor de texto, creamos el fichero cone.py. Lo primero es importar desde Python el paquete VTK; esto es tan sencillo como escribir la siguiente línea:

iren.Start() ren=vtk.vtkRenderer() renWin=vtk.vtkRenderWindow() renWin.AddRenderer(ren) iren=vtk.U vtkRenderWindowInteractor() iren.SetRenderWindow(renWin)

Para poder manipular la cámara mediante el ratón se ha instanciado el objeto vtkRenderWindowInteractor (denominado en el código como iren). Nótese que la ventana de renderizado renWin, se asocia al objeto de interacción iren

WWW.LINUX- MAGAZINE.ES

Si ejecutamos nuevamente el programa, cuál es nuestra sorpresa que se abre una ventana de color negro con sus botones de minimizar, maximizar y cerrar; y que sólo se cierra cuando el usuario lo estima oportuno (Figura 3). Esta ventana va a ser “el contenedor” de nuestra pequeña escena. Nótese que las dos líneas de código que acabamos de escribir deben de estar al final del fichero. Las demás líneas que escribamos a partir de este momento debemos situarlas justo antes.

Número 06

61


060-064_VTK_PythonLinux6

20.04.2005

14:10 Uhr

Página 62

DESARROLLO • Python

es un conjunto que se asoPara crear nuestro primer actor no nos cia al “mapper” (coneMapvamos a complicar demasiado, porque per) ya queremos ver algo. VTK (vtk.vtkPolycontiene una serie de clases DataMapper) que nos permiten crear vía el método objetos tridimensionales SetInput(). sencillos, como son: esfera Creamos el (vtkSphereSource), cono actor (objeto (vtkConeSource), cilindro que se va (vtkCilinderSource), etc. renderizar) al Para nuestro ejemplo que se le asohemos escogido un cono, Figura 5: Cono dentro de cia la represin embargo, puedes optar la escena. sentación por cualquiera de los otros geométrica que aporta objetos. El siguiente código nos permite coneMapper. Nótese que crear nuestro primer “actor”, Figura 4: Pasos que en general hay que seguir para crear un los pasos aquí indicados actor. son los que en general, cone=vtk.vtkConeSource() necesitamos seguir para poder consconeMapper=vtk.U Si volvemos a ejecutar visualizamos un truir un actor (Figura 4). cono de color gris (color que se muestra vktPolyDataMapper() Cuando creamos un actor, no se por defecto) dentro de nuestra ventana coneMapper.SetInput(cone.U incluye por defecto en la escena. Es (Figura 5). Además, es en este instante GetOutput()) necesario añadirlo al Renderer mediandonde se aprecia la interacción con el coneActor=vtk.vtkActor() te AddActor, y posteriormente renratón; con el botón izquierdo puedes coneActor.SetMapper(coneMapper) derizar la escena. Esto se logra escrirotar la cámara, el botón central permite biendo, trasladarla, y con el botón derecho nos Mediante el objeto vtk.vtkConeSource acercamos o alejamos del objeto. creamos una representación poligonal Además, habrás observado que en la de un cono, que hemos llamado cone. ren.AddActor(conoActor) escena, por defecto se incluye una luz La salida del cono (cone.GetOutput()) renWin.Render()

Listado 1: cono_esfera.py 01 import vtk 02 03 # Generamos la estructura para ver un cono 04 cone = vtk.vtkConeSource() 05 c o n e M a p p e r = vtk.vtkPolyDataMapper() 06 coneMapper.SetInput(cone.GetOu tput()) 07 coneActor = vtk.vtkActor() 08 coneActor.SetMapper(coneMapper ) 09 10 # C r e a r f u e n t e d e e s f e r a , mapeador y actor 11 esfera = vtk.vtkSphereSource() 12 e s f e r a M a p p e r = vtk.vtkPolyDataMapper() 13 esfera.SetPhiResolution(10) 14 esfera.SetThetaResolution(20) 15 esfera.SetCenter(0.3,0.0,0.0) 16 esferaMapper.SetInput(esfera.G etOutput()) 17 esferaActor = vtk.vtkActor()

62

Número 06

18 esferaActor.SetMapper(esferaMa pper) 19 esferaActor.GetProperty().SetC olor(0.7,0.0,0.25) 20 esferaActor.GetProperty().SetO pacity(0.75) 21 esferaActor.GetProperty().SetL ineWidth(1) 22 23 # C r e a m o s : R e n d e r e r , RenderWindow, RenderWindowInteractor 24 ren = vtk.vtkRenderer() 25 renWin = vtk.vtkRenderWindow() 26 renWin.AddRenderer(ren) 27 i r e n = vtk.vtkRenderWindowInteractor( ) 28 iren.SetRenderWindow(renWin) 29 30 # Añadimos el actor en el área de renderizado (Renderer) 31 ren.AddActor(coneActor)

WWW.LINUX- MAGAZINE.ES

32 ren.AddActor(esferaActor) 33 34 #Fijamos el color de fondo, el tamaño y hacemos zoom sobre 35 #el area de Renderizado 36 ren.SetBackground(1, 1, 1) 37 renWin.SetSize(450, 425) 38 camera=ren.GetActiveCamera() 39 ##camera.Zoom(1.5) 40 41 coneActor.RotateX(30) 42 coneActor.RotateY(45) 43 conepro=coneActor.GetProperty( ) 44 conepro.SetColor(0,0.6,1) 45 ##conepro.SetOpacity(0.5) 46 conepro.SetLineWidth(2) 47 ren.ResetCamera() 48 ##camera=ren.GetActiveCamera() 49 camera.Zoom(1.5) 50 51 cone.SetResolution(40) 52 53 iren.Initialize() 54 renWin.Render() 55 iren.Start():


060-064_VTK_PythonLinux6

20.04.2005

14:10 Uhr

Página 63

Python • DESARROLLO

Cuadro 1: Instalación de Fuentes VTK Para instalar VTK partir del código fuente, que podemos descargar desde la Web de VTK, http://www.vtk.org/ get-software.php, podemos elegir bajar una de las versiones en .tgz ó acceder al CVS y descargar la última versión. En el segundo caso crearemos una carpeta que se llame VTK en /opt y para acceder al repositorio CVS tecleamos: cvs -d :pserver:U anonymous@public.U kitware.com:/cvsrootU /VTK login @KL(responder con el password: vtk) Para bajar el código fuente tecleamos: cvs -d :pserver:U anonymous@public.U kitware.com:/cvsrootU /VTK checkout VTK En cualquier caso para compilar VTK, necesitaremos el CMake, que se puede obtener en http://www.cmake.org/ HTML/Download.html. Si lo preferimos también podremos obtener el CMake desde el CVS: cvs -d :pserverU :anonymous@www.cmake.U org:/cvsroot/CMakeU login password: cmake y para descargarlo:

para poder visualizar los objetos iluminados. Prueba a comentar la línea renWin.Render(). ¿Qué ocurre? Como te habrás dado cuenta el cono ya no aparece, esto es porque cada vez que añadimos un actor es necesario renderizar la escena, porque sino no se realiza un refresco de la misma y es como si no hubiésemos añadido un nuevo actor.

Propiedades de Objetos Si has seguido el tutorial hasta este punto, habrás creado tu cono de color gris. Pero probablemente no estés demasiado satisfecho, porque todos tenemos el mismo cono gris y tú lo querías blanco y el fondo azul, por ejemplo. A lo largo de este apartado veremos como modificar la ventana de renderizado, la cámara, propiedades del actor, etc. Al final, podrás realizar todos aquellos cambios que te apetezcan. Habrás observado que la ventana de renderizado se abre con un tamaño predeterminado. Para fijar el tamaño de dicha ventana es necesario emplear el método SetSize, donde indicamos el alto y el ancho en pixels, renWin.SetSize(450,325)

Si lo que pretendemos es cambiar el color de fondo de la escena (vtkRenderer) empleamos el método Set-

Tabla2: Modelo de Visualización Objeto Descripción vtkDataObject clase genérica que permite representar diferentes tipos de datos. Los objetos de datos consisten en estructuras geométricas y topológicas (puntos y celdas), y también en atributos asociados, tales como escalares o vectores. vtkProcessObject objeto que hace referencia a filtros, que actúan sobre los actores modificándolos.

Background(RGB), donde le pasamos el color deseado en formato RGB. Si queremos un fondo azul bastaría escribir ren.SetBackground(0.0, 0.0, 1)

Como dijimos, el área de renderizado (vtkRenderer) coordina la cámara y las luces. Mediante el método GetActiveCamera() se accede a la cámara creada en la escena, así podemos aplicarle todos los métodos del objeto vtkCamera para poder modificar la visualización según queramos. Si lo que pretendemos es que todos nuestros actores se vean en su totalidad dentro del área de renderizado es necesario llamar al método ResetCamera(). En las siguientes líneas se recogen algunos de los métodos relativos a la cámara ren.ResetCamera()

cvs -d :pserver:U anonymous@www.cmake.U org:/cvsroot/CMakeU co CMake Una vez hayamos descargado e instalado CMake, podemos compilar VTK. Para ello entraremos en la carpeta donde tenemos VTK y teclearemos desde la línea de comandos: cmake -i Nos preguntará lo que queremos compilar de forma interactiva: hemos de prestar atención y cuando nos pregunte si queremos instalar los wrappers para Python hemos de contestar afirmativamente ya que por defecto no lo hace. Después basta teclear: make make install

Figura 6:Comportamiento de los métodos de la cámara. a) Azimuth - flechas rojas; b) Pitch flechas azul celeste; c) Yaw - flechas azul oscuro; d) Elevation - flechas verdes; e) Roll flecha amarilla. La esfera blanca representa el foco.

WWW.LINUX- MAGAZINE.ES

Número 06

63


060-064_VTK_PythonLinux6

20.04.2005

14:10 Uhr

Página 64

DESARROLLO • Python

camera=ren.GetActiveCamera() camera.Azimuth(60) camera.Pitch(5) camera.Yaw(5) camera.Roll(50) camera.Elevation(20) camera.Zoom(1.5)

Los métodos Azimuth, Pitch, Yaw, Roll,Elevation se ocupan de rotar la cámara o el punto de foco en diferentes direcciones y, como argumento, se pasa un ángulo de rotación. Lo mejor es que juegues un poco con la cámara y veas lo que ocurre probando cada uno de estos métodos por separado. Por ejemplo, para ver como afecta el método Azimuth aplicado a la cámara, comenta las restantes lineas de código, porque sino estarías mezclando distintos métodos de rotación y uno así no sabe realmente lo que ocurre. Si en algún momento el actor desaparece de la escena no te preocupes, lo que está

Figure 7: Vista de la superficie del cono.

64

Número 06

conepro=coneActor.GetProperty() conepro.SetColor(1,0.2,0) conepro.SetOpacity(0.5) conepro.SetLineWidth(3) conepro.SetResolution(40) conepro.U SetRepresentationToWireframe()

La última línea de este código se indica que queremos ver la estructura básica que constituye el actor, es decir el mallado. Por defecto, VTK tiene asociadas teclas rápidas a la escena: si tecleas la letra “s” se ven todos los objetos renderizados (ver Figura 7), mientras que si tecleas la letra “w”, se visualiza sólo la malla (ver Figura 8). Ahora Figura 9: Escena con dos apreciarás mejor actores que se intersecan.

WWW.LINUX- MAGAZINE.ES

la diferencia entre mallado y estructura renderizada, no hay nada mejor que poder ver las cosas. La línea conepro.SetResolution(40) modifica la resolución con la que se renderiza el cono. Este método no es general para todos los actores, sino para ciertos objetos que VTK ya incluye, como son: esfera (vtkSphereSource), cono (vtkConeSource), cilindro (vtkCilinderSource), etc. Cualquier objeto puede rotarse, escalarse, obtener su dimensiones, etc., utilizando las propiedades de un vtkActor en particular(si queréis más información, basta consultar las ayuda de VTK sobre vtkProp3D, que es la clase padre). Para rotar nuestro cono y escalarlo basta escribir coneActor.RotateX(30) coneActor.RotateY(45) coneActor.SetScale([1,3,2])

Ahora ya sabéis crear vuestra propia escena, modificar sus propiedades, añadir un actor con las opciones que queráis y modificar la cámara. En caso de que quisierais añadir más actores a vuestra ventana de renderizado basta seguir el mismo procedimiento que hemos empleado para crear nuestro cono. En el Listado 1 se añade a la escena un cono y una esfera que se intersecan (Figura 9). ■

RECURSOS [1] RPMs VTK de Mandrake: ftp://ftp. rediris.es/sites3/carroll.cac.psu.edu/ mandrakelinux/official/10.1/i586/ media/contrib/ [2] Kitware. VTK: http://www.kitware.org [3] Enthought. Scientific python: http:// www.scipy.org [4] MayaVi: http://mayavi.sourceforge.net [5] Código de este artículos: http://www. linux-magazine.es/Magazine/ Downloads/05

LOS AUTORES

Figura 8: Vista de la malla del cono.

sucediendo es que el ángulo de rotación ha colocado la cámara justo en un punto que evita que visualicemos el objeto dentro de la escena. En la Figura 6 explica de un modo sencillo el modo en que actúan cada uno de estos métodos respecto del foco (representado por una esfera blanca). A partir de este punto comentad las líneas de código correspondientes a los métodos que actúan sobre la cámara, dejando únicamente la línea camera.Zoom(1.5). Así vamos viendo cada cosa por separado, después ya tendréis tiempo de mezclar código. Ahora que sabemos modificar la escena, debemos recordar que el cono continúa viéndose en un color gris un poco apagado. Para acceder a las propiedades de cualquier actor vtkActor se emplea el método GetProperty(), que devuelve una instancia del objeto vtkProp asociado a dicho actor. Las siguientes líneas permiten modificar el color, la transparencia y grosor de las líneas:

Ana M. Ferreiro Ferreiro y José A. García Rodríguez estudiaron matemáticas, pero la informática les apasiona, y a ella dedican gran parte de su tiempo.


3d,grafica