Caso de estudio

Què t'agradaria fer?

Algo com Figura 9-9:

Figura 9-9. Proposta de una BD de pacientes: MEDICAL.

Base de datos de imágenes: introducción a la recuperació por contenido de información visuagl.

Figura 9-10. Recuperando información de una base de datos de imágenes.

Se trata de desarrollar un interfaz que permita la interacción con programas externos para selecciónar una image (o una parte de la misma) y buscar a partir de esta selección en una base de datos de imágenes las que sean similares. El resultado de esta búsqueda es la visualización de las imágenes que han respondido satisfactoriamente a la consulta ordenadas por un criterio de similitud.

El primer paso

Elaborar un sencillo interfaz que permita explorar las posibilidades de seleccionar la imagen de partida y una parte de la misma mediante una banda de goma (rubberband) o la imagen al completo (la opción por defecto). La pila proporciona un mecanismo para cargar un fichero de disco (debería ser también una URL) y a partir de la visualización de esta permite escoger un rectángulo de la misma o, si no se indica tal, la toma al completo. Además deberá hacer uso de un programa externo para recortar el trozo de interés en el caso oportuno.

Figura 9-11. Recuperando información de una base de datos de imágenes.

/*
 La pila
 */
on openCard
 put the directory into field "directoriDeTreball"
 set itemDelimiter to "/"
 delete last item of  field "directoriDeTreball"
 delete last character of  field "directoriDeTreball"
end openCard

/*
 Control: image gImatgeOriginal
 */
on mouseEnter
  set the cursor to cross
  set the lockCursor to true
end mouseEnter

on mouseLeave
  set the cursor to hand
  send "bandaInactiva" to graphic "bandaElastica"
end mouseLeave


on mouseDown
  send "bandaActiva" to graphic "bandaElastica"
end mouseDown


on mouseUp
  send "bandaInactiva" to graphic "bandaElastica"
  -- export paint to file "retall"
  send "mostraImatge" to image "mostra"
end mouseUp


on mouseMove x,  y
  send ("actualitzaBanda " & x & "," & y) to graphic "bandaElastica"
end mouseMove



/*
 Control: image "mostra"
 */
on mostraImatge
  # Hi ha que donar-li temps
  send "mouseUp" to me in 250 milliseconds
end mostraImatge

on mouseUp
  set the filename of me to empty
  set the filename of me to (the field "directoriDeTreball" & "/" &"retall")
  put (the field "directoriDeTreball" & "/"& "retall")
end mouseUp


/*
 Control: button bAbrir
 */
on mouseUp
  answer file "Tria un fitxer" with filter "*.*"
  if it is not empty
  then set the fileName of the image "gImatgeOriginal" to it
end mouseUp


/*
 Control: graphic bandaElastica
 */
local x0, y0, \
    x1, y1, estesNoFanFaltaPerAraComprobahhoooo,\
    seguintLaBandaElastica

on bandaActiva
  put the first item of the mouseLoc into x0
  put the second item of the mouseLoc into y0
  set the rectangle of me to x0,y0,x0,y0
  put true into seguintLaBandaElastica
end bandaActiva

on bandaInactiva
  put false into seguintLaBandaElastica
  put shell( "pnmcut" && \
      the first item of the rect of me - the first item of the rect of image "gImatgeOriginal" && \
      the second item of the rect of me - the second item of the rect of image "gImatgeOriginal" && \
      the third item of the rect of me - the first item of the rect of me && \
      the fourth item of the rect of me - the second item of the rect of me && \
      the filename of image "gImatgeOriginal" && "> " &\
      the field "directoriDeTreball" & "/"& "retall") into it
  if the result is 0 then send "mostraImatge" to image "mostra"
end bandaInactiva

on actualitzaBanda x,  y
  if (seguintLaBandaElastica) then \
      set the rectangle of graphic "bandaElastica" to \
      x0,y0,\
      min( the third item of the rect of image "gImatgeOriginal", x), \
      min( the fourth item of the rect of image "gImatgeOriginal",  y )
end actualitzaBanda
              

Comunicación con el usuario y las aplicaciones externas

En esta parte el objetivo es poner en marcha el interfaz que va a permitir la interacción con el usuario, así como con las aplicaciones a ejecutar para llevar a cabo los procesos "específicos" a los que da un entorno integrador la aplicación en MetaCard. Las acciones del usuario se llevaran a cabo mediante la selección de la parte de la imagen descrita en el apartado anterior y mediante el uso del menú. Por su parte, queda por exponer el mecanismo de llamada a la aplicación externa encarga de realizar un proceso dentro de la tarea global para la cual estamos creando el interfaz.

Para la creación del menú se ha utilizado la herramienta que acompaña a la barra de menú de MetaCard: Tools|Menu Builder.... Desde esta se puede crear de una forma cómoda el mismo. A este se le han hecho un par de modificaciones:

Las aplicaciones que realizan las actividades de análisis de imágenes se han implementado mediante programas, haciendo así el papel de aplicaciones externas. La salida de estas deber permitir realizar los subsecuentes análisis y tomar las decisiones. En este punto es donde, de nuevo, entra en juego el interfaz que estamos desarrollando. Puesto que podemos hacer uso de la sencilla comunicación que permite ejecutar aplicaciones mediante las órdenes shell o launch y obtener los resultados en forma de texto que la ejecución de estas deja en la salida estándar.

Para facilitar la programación desde MetaCard con la versión del Starter Kit así como la depuración de errores utilizaremos campos de texto como contenedores de esa información que se obtenga. Después sólo habrá que analizar el texto cuyo formateado habrá sido elaborado con esa intención, ya que en este caso hemos programado tales ejecutables para facilitar este paso.

Figura 9-12. Elementos de comunicación con el usuario y las aplicaciones externa."Para't, para't!".

-- button "analizar"
on mouseUp
  set the lockCursor to false
  set cursor to busy
  #Executa l'analisis
  put shell( field "analitzaor" && mostra.ppm) into field "resultatAnalisi"
end mouseUp
              

Aprovecho que hemos abordado la cuestión de la versión de MetaCard para justificar la decisión que se ha tomado para implementar los eventos asociados a los menús.

Figura 9-13. Menú de la aplicación

-- En la tarjeta
on resizeStack
  send "resizeStack" to group "menuGroup"
end resizeStack


-- En el grupo 'menuGroup'
on resizeStack
  set the lockLocation of me to true
  set the width of me to the width of this card
  set the width of button "menuButton" of me to the width of me - 6
  set the left of button "menuButton" of me to 4
  set the right of button "Ajuda" of me to the right of me - 4
  --  pass resizeStack
end resizeStack


-- Botón Ajuda
on menuPick which
  send "mouseUp" to button which
  
  #switch which
  #case "Help..."
  #  break
  #case "About..."
  #  break
  #end switch
end menuPick
              

Programación secuencial frente a Eventos/Mensajes

En esta tercera parte nos vamos a centrar en cómo se puede implementar un mecanismo que permita interrumpir un proceso prolongado. En este caso, se refiere a las acciones propias de extracción de información de la BD de imágenes y a la secuencia de presentación de resultados.

Figura 9-14. Mecanismo de parada asíncrona: botón "Para't, para't!".

global gInterrumpeixUsuari, timerID

on mouseUp
  put "true" into gInterrumpeixUsuari
  cancel timerID
  hide scrollBar "barraEstatProgres" of group "barraEstat"
  put empty into field "barraEstatMensatges" of group "barraEstat"
  
  #Deixem-ho preparat per a la proxima
  put "false" into gInterrumpeixUsuari
end mouseUp