Visualización Gráfica 3D con VTK (Visualization Toolkit) (2ª parte)

download Visualización Gráfica 3D con VTK (Visualization Toolkit) (2ª parte)

of 5

Transcript of Visualización Gráfica 3D con VTK (Visualization Toolkit) (2ª parte)

  • 7/31/2019 Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    1/5

    Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    INTERFAZ GRFICA 3D

    Vemos como crear una Interfaz Grfica de Usuario (GUI) que contenga un rea de renderizado y diferentes

    widgets que permitan modificar,propiedades de la escena, de los actores, etc.

    POR ANA M. FERREIRO Y JOS A. GARCA

    En el nmero 6 de Linux

    Magazine, vimos como crear una

    escena de renderizado en la que

    incluimos diferentes actores, a los que

    modificamos sus propiedades. Sin

    embargo, lo mejor es tener un Interfaz

    Grfico (GUI) que permita a cualquier

    usuario, sin necesidad de entender el

    cdigo, modificar cualquier propiedad de

    los actores, del rea de renderizado, etc.

    Hoy por hoy, existen diferentes tool-

    kits de ventanas que se pueden impor-

    tar desde Python, y que adems constan

    de un widget especfico para contener

    un rea de renderizado de VTK. Entre

    las diferentes herramientas grficas,

    cabe destacar Tkinter, WxPython,

    PythonQT y Motif; siendo TKinter la

    opcin por la que nos hemos decidido,

    puesto que por defecto se incluye en

    cualquier instalacin de Python.

    En lo que sigue veremos los pasos

    necesarios para incluir una escena de

    VTK dentro de una GUI generada conTkInter, para terminar incluyendo dos

    botones, uno que nos permita modificar

    alguna propiedad del objeto que haya-

    mos colocado en nuestra escena y otro

    que capture el contenido de la escena

    para guardarla en una imagen .tiff.

    En el Listado 5, tenis escrito el cdi-

    go completo. Lo mejor es que cada vez

    que tengis dudas lo miris, as os va a

    ser ms fcil seguir cada uno de los

    pasos que se os proponen.

    Interpretacin de una GUIEn el nmero 6 de la revista vimos que

    al crear una escena VTK se abre una

    ventana de renderizado, que permite la

    interaccin con el ratn. Sin embargo,

    dicha escena ocupa la totalidad de la

    ventana. Al combinar VTK con TkInter

    podremos colocar la escena de VTK en

    un panel concreto de la GUI, segn nos

    interese.

    Para que resulte sencillo diferenciar

    los mtodos propios de la GUI de los

    mtodos relacionados con el renderiza-

    do de la escena, vamos a organizar el

    trabajo siguiendo una estructura de cla-ses.

    Si lo pensis bien, una GUI que con-

    tenga un rea de renderizado (Figura

    1), se puede comparar con un televisor.

    El televisor con los botones y la panta-

    lla, lo podis imaginar como la interfaz

    de usuario que contiene el rea de ren-

    derizado; mientras que lo que vemos,

    segn el canal que se sintonice, va a ser

    la escena de VTK. Todo esto nos lleva a

    organizar, de un modo natural, nuestro

    programa en dos clases (Figura 2):

    1) class MyGUI: clase que controla la

    estructura de la GUI, es decir, los boto-

    nes, los paneles, los mens, los eventos

    asociados a los widgets, etc.

    2) class RenderWindow: clase que

    controla el rea de visualizacin, la

    escena, los actores, las propiedades de

    los objetos, la cmara, el renderizado,

    los eventos asociados al rea de rende-

    rizado, etc.

    NOTA: Para mejor seguir este artcu-

    lo, conviene tener a manos el cdigo

    completo del programa, que se puede

    descargar desde [6].

    Creacin GUI TKInterLo primero de todo es importar Tkinter

    y VTK,

    DESARROLLO Infografa - VTK

    62 Nmero 08 WWW.L INUX- M A GA ZINE.ES

  • 7/31/2019 Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    2/5

    Infografa - VTK DESARROLLO

    63Nmero 08WWW.L INUX- M A GA ZINE.ES

    padre, root, en el que colocamos los fra-

    mes fr_renwin y fr_bot, en la parte supe-

    rior y en la parte inferior, respectivamen-

    te. Esta organizacin se corresponde con

    el cdigo del Listado 1.

    Para instanciar la clase MyGUI, debe-

    mos hacerlo indicando que rootva a ser

    la ventana padre que contenga los dife-

    rentes widgets que vamos a ir creando.

    Esto se indica escribiendo las siguientes

    lneas de cdigo.

    root = Tkinter.Tk()

    app=MyGUI(root)

    root.minsize(350, 300)

    root.mainloop()

    Guardad este cdigo en un fichero lla-

    mado, miguivtk.py, por ejemplo. Si lo

    ejecutis (python miguivtk.py), se os

    abre una ventana con los dos frames

    (ver Figura 3).

    Widget vktRenderWindowLa clase vtkTkRenderWidgetes un wid-

    get de Tk, que permite renderizar en

    su interior. Mediante el mtodo

    GetRenderWindow se devuelve una

    ventana de renderizado,

    vtkRenderWindow, a la que se

    le puede asociar un rea de

    renderizado vtkRenderer.

    Este widget puede reaccio-

    nar a los eventos (de ratn, de

    teclado) como cualquier otro

    widget de Tk. Para poder utili-

    zar este widget necesitamos enprimer lugar importarlo,

    import vtkRenderWidget

    Creamos la claseRenderWindow que se

    va a encargar de todo lo relacionado

    con la visualizacin, es decir, con el

    renderizado, el control de la cmara y

    las luces, el tipo de interaccin del

    usuario con la escena, etc.

    class RenderWindow:

    El constructor de esta clase se va a

    encargar de instanciar

    vtkTkRenderWidget, crear el rea de

    renderizado y sus propiedades.

    Recordad que vtkTkRenderWidgetes un

    tipo de widget de Tk, por tanto, es nece-

    sario decirle cual va a ser su widget

    padre, pasndolo como argumento cada

    vez que instanciemos nuestra clase

    RenderWindow. En el Listado 2 tenis el

    cdigo correspondiente a dicho cons-

    tructor.

    Instanciamos la clase

    vtkTkRenderWidgetpara crear un wid-

    get de Tk (que hemos llamado

    self.vtktkwidget), indicando que su

    padre esparent. Mediante self.ren =

    vtkpython.vtkRenderer()se crea un rea

    de renderizado de VTK, que aadimos a

    la ventana de renderizado que tiene

    asociada el widget self.vtktkwidget. A

    dicha ventana se accede mediante elmtodo GetRenderWindow. Mediante el

    mtodo TwoSidedLightingOn colocamos

    dos luces encendidas en nuestra escena.

    El mtodo GetActiveCamera() permite

    obtener la cmara que por defecto viene

    incluida en la escena.

    Si ejecutamos de nuevo el cdigo

    nada ha cambiado! La razn es obvia:

    Desde la GUI no hemos instanciado

    nuestra claseRenderWindow. En

    el constructor

    import vtk

    import Tkinter

    La interfaz la vamos a organizar en dos

    frames: fr_renwin donde se colocar

    la ventana de renderizado y fr_gui quecontendr los diferentes botones.

    Inicializamos Tkinter, creando una

    ventana padre root, root=Tkinter.Tk(),

    en la que colocaremos los frames fr_ren-

    win y fr_gui. Es necesario que nuestra

    ventana permanezca abierta hasta que

    el usuario decida cerrarla, lo que se

    logra mediante root.mainloop().

    Segn la organizacin que hemos

    propuesto, tenemos la clase MyGUI,

    que se ocupa de los widgets de la

    interfaz,

    class MyGUI:

    En el constructor de la clase es necesario

    indicarle quien va a ser el contenedor

    01 def __init__(self,parent):

    02 self.parent=parent

    03 parent.title("Mi GUI")

    04 fr_renwin =

    Tkinter.Frame(parent,bg="gray"

    )

    05 fr_bot=

    Tkinter.Frame(parent)

    06

    fr_renwin.pack(side="top",

    anchor="n",

    07

    expand=1, fill="both")

    08 fr_bot.pack(side="bot-

    tom", anchor="s",

    09expand="t", fill="x")

    10 lsup = Tkinter.Label(

    fr_renwin,

    11

    text="Frame de la

    escena",fg="red")

    12 lsup.pack(side="top",

    expand="t")

    13

    14 l1 =

    Tkinter.Label(fr_bot,

    text="Frame de botones")

    15 l1.pack(side="top",

    expand="t", fill="x")

    16 parent.update()

    Listado 1: Constructorclase MyGUI

    Figura 1: Estructura de una GUI con una ven-

    tana de renderizado.

  • 7/31/2019 Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    3/5

    DESARROLLO Infografa - VTK

    WWW.L INUX- M A GA ZINE.ES

    (__init__) de la claseMyGUI, debemos

    instanciar la clase RenderWindow.

    Basta aadir en dicho constructor las

    sigientes lneas de cdigo

    self.renwin=U

    RenderWindow(fr_renwin)

    Fijaos que como argumento pasamos

    fr_renwin, esto es porque el widget que

    contiene el rea de renderizado lo situa-

    mos dentro de dicho frame.

    Ahora la ejecucin ha cambiado.

    Tenemos un rea de color azul, que es

    el rea de renderizado de la escena

    (ver Figura 4). Seguro que os pregun-

    taris, cmo s yo que es un rea de

    renderizado y no un simple frame de

    color azul? Por el momento no hemos

    creado ningn actor para que se apre-

    cie la diferencia, sin embargo, si cerra-mos la ventana obtenemos el siguiente

    warning: A TkRenderWidget is being

    destroyed before its associated

    vtkRenderWindow is destroyed.

    Dicho mensaje, que antes no tena-

    mos, nos avisa de que debemos des-

    truir la ventana de renderizado antes

    que el widget que la contiene, porque

    en ciertas ocasiones podran quedar

    procesos corriendo sin que lo aprecie-

    mos.

    Antes de nada, debemos decirle a

    nuestra GUI qu hacer cuando se activa

    el protocolo WM_DELETE_WINDOW

    (define lo que ocurre cuando el usuario

    explcitamente cierra la ventana

    mediante el botn cerrar). En el cons-

    tructor de la clase MyGUI debemos

    escribir,

    parent.protocol(U

    "WM_DELETE_WINDOW",

    self.quit)

    El mtodo que estamos lla-mamos al cerrar la ventana

    es self.quit,

    def quit(self):

    self.parent.quit()

    Volvamos a ejecutar el cdigo. Fijos

    que ya no aparece ninguna advertencia

    al cerrar la ventana. De este modo des-

    truimos los distintos objetos instancia-

    dos en el orden correcto.

    Actores a EscenaEn este punto ya tenemos todo lo nece-

    sario para incluir actores en la escena.

    En la claseRenderWindow tenemos que

    crear los siguientes mtodos: (1)

    add_actor: aade un actor a la escena;

    (2) render_window: se ocupa del rende-

    rizado de la escena; (3) resetcamera: se

    ocupa de resetear la cmara y rende-

    rizar la escena, permitiendo ver la tota-

    lidad de la escena. Basta escribir las

    siguientes lneas de cdigo,

    def add_actor(self,nameactor):

    self.ren.AddActor(nameactor)

    def render_window(self):

    self.renwin.Render()

    def resetcamera(self,evt=None):

    self.ren.ResetCamera()

    self.renwin.Render()

    En la escena vamos a

    situar una esfera; para

    ello, dentro de la clase

    RenderWindow incluimos,

    las funciones create_esfera

    y add_esfera del Listado 3.

    El mtodo create_esferaconstruye una esfera

    segn los mtodos propor-

    Nmero 0864

    01 def create_esfera(self):

    02 esfera =

    vtk.vtkSphereSource()

    03 esferaMapper =

    vtk.vtkPolyDataMapper()

    04

    esfera.SetPhiResolution(10)

    05

    esfera.SetThetaResolution(20)

    06

    esfera.SetCenter(0.3,0.0,0.0)

    07

    esferaMapper.SetInput(esfera.G

    etOutput())

    08 esferaActor =

    vtk.vtkActor()

    09

    esferaActor.SetMapper(esferaMa

    pper)

    10

    esferaActor.GetProperty().SetC

    olor(0.7,0.0,0.25)

    11esferaActor.GetProperty().SetO

    pacity(1)

    12

    esferaActor.GetProperty().SetL

    ineWidth(1)

    13 return esferaActor

    14

    15

    16 def add_esfera(self):

    17

    self.esfera_actor=self.crea-

    te_esfera()

    18 self.add_actor(self.esfe-

    ra_actor)

    19 self.render_window()

    Listado 3: Mtodos clase

    RenderWindow para crearuna esfera.

    Figura 2: Clases del programa.

    01 def __init__(self, parent):

    02 self.vtktkwidget =

    vtkRenderWidget.vtkTkRenderWid

    get (parent)

    03 self.vtktkwidget.pack

    (expand='true',fill='both')04 self.ren =

    vtk.vtkRenderer ()

    05

    self.ren.TwoSidedLightingOn ()

    06 self.renwin =

    self.vtktkwidget.GetRenderWind

    ow ()

    07

    self.renwin.AddRenderer

    (self.ren)

    08 self.camera =

    self.ren.GetActiveCamera()

    09

    self.ren.SetBackground(0.1,

    0.1, 0.9)

    Listado 2:Constructor claseRenderWindow.

    Figura 3: Ventana de

    Tkinter con dos frames.

  • 7/31/2019 Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    4/5

    cionados por VTK (en el nmero 6

    explicamos el modo de crear un actor y

    acceder a sus propiedades), devolvien-

    do el actor esferaActor. El mtodo

    add_esfera incluye todos los comandos

    necesarios para colocar la esfera dentrode nuestra escena.

    Llamemos a la funcin add_esfera,

    dentro del constructor de la clase

    RenderWindow,

    self.add_esfera()

    Si habis seguido todos los pasos, debe-

    rais estar viendo dentro de la escena

    una esfera, igual que la

    de la Figura 5. Seguro que

    alguien se est preguntan-

    do: Por qu no veo la

    esfera en su totalidad?

    Recordad que el mesanterior, explicamos que

    cuando situamos un actor

    en la escena, no se modi-

    fica la posicin de la

    cmara. Por tanto, si que-

    remos ver la escena en su

    totalidad basta resetear

    la camara. Como somos

    previsores, ya habamos

    creado el mtodo resetca-

    mera para dicha finali-

    dad. Basta escribir

    self.resetcamara(), justo

    despus de self.add_esfe-

    ra(). Ahora ya vemos la

    esfera centrada en la esce-

    na (Figura 6).

    Recordaris que dentro

    de la ventana de renderi-

    zado se puede interactuar

    con el ratn. Probad a

    trasladar la esfera, hacer zoom, etc. No

    os resulta ms sencillo mover la esfera

    que en los ejemplos que vimos en el

    nmero 6? Si lo comparis, os dariscuenta de que el actor se traslada y rota

    de un modo diferente. La razn de esto

    es que se pueden modificar el modo de

    interactuar con el ratn dentro de una

    ventana de renderizado de VTK. En este

    caso concreto, la clase

    vtkTkRenderWidgetya crea una ventana

    de renderizado donde el tipo de interac-

    cin con el ratn ya viene modificado,

    para que podamos controlar mejor los

    diferentes actores.

    Control de EscenaHasta ahora lo que hemos implementa-

    do nos permite abrir una

    ventana de TkInter que con-

    tiene un rea de renderiza-

    do, cuya escena ya contiene

    una actor. Pero la finalidad

    de crear una interfaz grfi-

    ca, es que

    mediante

    widgets

    podamos

    controlar,en la medi-

    da de lo

    posible,

    los actores, la escena,

    etc.

    Dentro de nuestra ven-

    tana vamos a incluir, en

    el frame fr_bot, los

    siguientes widgets: undeslizable (Tkinter.Scale)

    para controlar la transpa-

    rencia de la esfera; un

    botn que nos permita

    guardar la escena en una

    imagen en formato .tiff y

    un botn para cerrar la

    aplicacin. Escribamos en

    el constructor (__init__)

    de la clase MyGUI, las

    lneas de cdigo del

    Listado 4.

    El deslizable s_transp

    llama al mtodo

    self.ModifyTransp cuando

    se pulsa el botn izquier-

    do del ratn (evento

    ) o se despla-

    za el ratn con dicho

    botn presionado (evento

    ). Al clicke-

    ar con el ratn sobre el botn bsave, se

    llama al mtodo self.guardar_imagen;

    mientras que si se pulsa bquitse ejecta

    self.quit. El mtodo self.quitya lo tene-mos, as basta escribir el cdigo corres-

    pondiente para los otros dos mtodos.

    Antes de detallar cada mtodo por sepa-

    rado, debemos comprobar que la estruc-

    tura de nuestra GUI es correcta. Para no

    tener problemas a la hora de probar el

    programa, por el momento escribid,

    Infografa - VTK DESARROLLO

    65Nmero 08WWW.L INUX- M A GA ZINE.ES

    s01 .02 .

    03 .

    04 self.transp_valor =

    Tkinter.IntVar()

    05 self.transp_valor.set(100)

    06 s_transp =

    Tkinter.Scale(fr_bot,from_=0,t

    o=100,

    07

    orient="horizontal",

    08

    variable=self.transp_valor,

    09

    label="Transparencia")

    10 s_transp.pack(side="top",

    fill="x", expand="false")

    11

    s_transp.bind("",lam

    bda e:self.ModifyTransp(e))

    12

    s_transp.bind("",la

    mbda e:self.ModifyTransp(e))

    13

    14 bsave= Tkinter.Button(fr_bot,

    text="Guardar Imagen",

    15

    command=self.guardar_imagen)

    16 bsave .pack(side="top",

    expand="t")

    17 bquit = Tkinter.Button(fr_bot,

    text="Salir",

    18 com-

    mand=self.quit)

    19 bquit .pack(side="top",

    expand="t")20 .

    21 .

    22 .

    Listado 4: Deslizable y

    Botones GUI

    Figura 4: GUI con un rea

    de renderizado.

    Figura 5: GUI con una esce-

    na que contiene una esfera

    como actor.

  • 7/31/2019 Visualizacin Grfica 3D con VTK (Visualization Toolkit) (2 parte)

    5/5

    Tened en cuenta, que

    para generar la imagen,

    es necesario tener permi-

    sos de escritura en el

    directorio donde se vaya

    a guardar; en caso con-trario nos saldra un

    error en la ejecucin avi-

    sando de que no es posi-

    ble generar dicha ima-

    gen.

    Probad de nuevo el

    programa y pulsad el

    botn Guardar Imagen.

    En principio parece que

    no hemos hecho nada,

    pero en el mismo directo-

    rio de trabajo tenis un

    fichero llamado mysce-

    ne.tif, donde se almace-

    na exactamente la ltima

    escena que hemos rende-

    rizado.

    Recordad que nos falta

    implementar el cdigo

    para modificar la transpa-

    rencia de nuestra esfe-

    ra. En la clase RenderWindow inclui-

    mos el mtodo

    modify_opacity_esfera(self,valor), donde

    valorvara entre 0 y 1, porque es el argu-mento que vamos a utilizar para fijar la

    opacidad. Escribamos las siguientes lne-

    as de cdigo,

    def modify_opacity_esferaU

    (self, valor):

    self.esfera_actor.GetProperty()

    U

    .SetOpacity(valor)

    self.render_window()

    Queremos que cada vez que deslizamos

    el widget s_transp, vare la transparen-

    cia de nuestro actor. Para ello, dentro de

    la clase MyGUI escribimos el siguiente

    cdigo correspondiente al mtodo

    ModifyTransp,

    def ModifyTransp(self,evtU

    =None):

    valor_transp=U

    self.transp_valor.get()

    valor_transp=U

    valor_transp/100.0

    self.renwin.U

    modify_opacity_esferaU

    (valor_transp)

    Mediante self.transp_

    valor.get() se obtiene el

    nuevo valor del Slice

    s_transp cada vez que se

    modifica ante un evento

    del ratn. Fijos que losvalores del deslizable var-

    an entre 0 y 100, sin

    embargo, el mtodo que

    modifica la transparencia

    slo admite valores entre 0

    y 1, por eso dividimos

    valor_transp por 100.

    Despus se llama al mto-

    do modify_opacity_esfera

    de la claseRenderWindow.

    Si habis seguido todos

    los pasos, comprobaris

    como se modifica la trans-

    parencia de la esfera a

    medida que varan los

    valores del deslizable.

    Ahora que ya sabis todo

    lo necesario para crear una

    GUI con una ventana de

    renderizado de VTK, podis

    hacer todas las pruebas que

    se os ocurran, como por ejemplo: modifi-

    car propiedades de la escena, controlar

    mediante widgets diferentes actores, etc. s

    def ModifyTransp(self,U

    evt=None):

    pass

    def guardar_imagen(self,U

    evt=None):pass

    Ahora la GUI tendra que tener la

    estructura de la Figura 7, donde el nico

    botn que funciona es el de Salir.

    Para implementar el mtodo guar-

    dar_imagen de la claseMyGUIva a ser

    necesario acceder, desde la clase

    MyGUI, a la ventana de renderizado

    (renwin) de la clase RenderWindow.

    Para ello,dentro de RenderWindow

    escribimos el siguiente mtodo,

    def get_renwin(self):

    return self.renwin

    El Listado 5 contiene el cdigo que nos

    permite guardar la escena en una ima-

    gen, de formato .tiff.

    La clase vtkWindowToImageFilteres

    un filtro que convierteRenderWindows

    o ImageWindows al formato de una

    imagen; produciendo una imagen de la

    escena de renderizado. La salida de este

    filtro se pasa como argumento a la clasevtkTIFFWriter, que se ocupa de escribir

    la imagen en formato TIFF. Mediante

    writer.SetFileName("myscene.tif") indi-

    camos el nombre del fichero en el que

    vamos a guardar la imagen.

    DESARROLLO Infografa - VTK

    66 Nmero 08 WWW.L INUX- M A GA ZINE.ES

    Ana M. Ferreirro Ferreiro es mate-

    mtica, pero su verdadera pasin

    es la informtica. As que parte de

    su tiempo lo dedica al desarrollo

    en Python de interfaces grficas

    multiplataforma, y al desarrollo de

    software de visualizacin cientfi-

    ca 3D.

    Jos A. Garca Rodrguez tambin

    es matemtico, y actualmente

    est finalizando su tesis en la

    Universidad de Mlaga. Desde

    hace unos aos se dedica al des-

    arrollo de cdigo paralelo y opti-

    mizacin de cdigos en C++.

    LOS

    AUTORES

    [1] Kitware. VTK:http://www.kitware.org

    [2] Python: http://www.python.org

    [3] Enthought. Scientific python: http://

    www.scipy.org

    [4] Rediris Espaa:ftp://ftp.rediris.es/

    [5] MayaVi: http://mayavi.sourceforge.net

    [6] Descarga de los Listados completos

    correspondientes a este artculo:

    http://www.linux-magazine.es/

    Magazine/Downloads/08

    RECURSOS

    01 def

    guardar_imagen(self,evt=None):

    02 w2imgfil =vtk.vtkWindowToImageFilter()

    03 writertiff =

    vtk.vtkTIFFWriter()

    04 w2imgfil

    .SetInput(self.renwin.get_ren-

    win())

    05 w2imgfil .Update()

    06 writertiff.SetInput(w2img-

    fil .GetOutput())

    07

    writertiff.SetFileName("mysce-

    ne.tif")

    08 self.renwin.render_win-

    dow()

    09 writertiff.Write()

    Listado 5: Mtodo GuardarImagen de Tipo .tiff

    Figura 6: Recolocacin de

    la cmara.

    Figura 7: GUI con deslizable

    y botones.