jueves, 9 de mayo de 2013

Biblioteca de clases para tratamiento digital de imágenes. ClaseImagenes.dll. Parte XVI.

Hoy os voy  mostrar una biblioteca de clases denominada ClaseImagenes.dll, desarrollada en Visual Basic .NET (disponible aquí), siendo ésta compatible con Microsoft .NET Framework 4. Aunque se ha desarrollado sobre Framework 4, la mayoría del código es compatible con Framework 2, por lo que se puede desarrollar una aplicación sirviéndose de ClaseImagenes.dll aunque la aplicación esté destinada para clientes Framework 2. Además, gracias al ecosistema .NET, la biblioteca puede ser utilizada desde cualquier otro lenguaje del entorno, como es C# o F#.
La biblioteca está compuesta por una gran cantidad de funciones para tratamiento digital de imágenes, desde transformaciones a escala de grises, binarización, hasta otras más complejas como grabar secuencias de transformaciones para poder automatizarlas. Esta biblioteca engloba todo el proceso de creación de una aplicación, incluye multitud de transformaciones, gestión de deshacer/rehacer imágenes, zoom, etc.
Una vez que se haya descargado la biblioteca para empezar a utilizar sólo hay que abrir Visual Studio y agregarla como referencia.

Agregar referencia

Una vez pulsado Agregar referencia, buscamos la biblioteca de clases descargada y aceptamos.

Agregando referencia

Ahora ya podemos empezar a utilizarla, y como primer ejemplo, vamos a ver cómo crear un objeto de la clase. Primeramente indicar que la clase se llama TratamientoImagenes, y está dentro de los espacios de nombres ClaseImagenes y Apolo. El código sería el siguiente:
'Creamos objeto de la clase ClaseImagenes
Dim objetoImagen As New ClaseImagenes.Apolo.TratamientoImagenes
A partir de esto, ya podemos empezar a aplicar multitud de transformaciones a una imagen (entre otros). Vamos a ver cómo transformar una imagen a tonos sepia:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'Transformamos la imagen a Bitmap
     Dim ImagenBMP As New Bitmap(PictureBox1.Image)
     'Instanciamos a la clase
     Dim objetoImagenes As New TratamientoImagenes
     'Asignamos al otro Picturebox el resultado de transformar a tonos sepia
     PictureBox2.Image = objetoImagenes.sepia(ImagenBMP)
End Sub
Y el resultado sería el siguiente:

Transformación a tonos sepia

Como puede observarse el proceso es muy sencillo, simplemente hay que transformar la imagen a Bitmap, crear un nuevo objeto de la clase (instanciar la clase) y llamar a la función que devolverá la imagen transformada. Si quiere ahorrarse un poco de código, puede incluir la siguiente sentencia al principio del código.
Imports ClaseImagenes.Apolo
Y la forma de instanciar la clase sería:
'Creamos objeto de la clase ClaseImagenes
Dim objetoImagen As New TratamientoImagenes


REFERENCIA DE MIEMBROS DE LA CLASE 

Para ver cómo funcionan las diferentes funciones, propiedades, eventos, etc., de la biblioteca ClaseImagenes.dll puede revisar la documentación técnica creada con SandCastle (disponible aquí) o bien utilizar el examinador de objetos de Visual Studio.
Para utilizar esta última forma, simplemente y tras agregar la biblioteca a su proyecto, hay que pulsar en el menú Ver/Examinador de objetos, y se mostrarán todas las funcionalidades de las clases, con ejemplos, explicación de parámetros y comentarios. Y de esta forma podrá ver todos los miembros de la clase y su funcionalidad. En la siguiente imagen se muestra lo explicado.

Examinador de objetos

Además, como toda la biblioteca está documentada de acuerdo al procedimiento de Visual Studio y sus comentarios XML, al llamar a cualquier miembro de la clase o a sus parámetros, se muestra toda la información en IntelliSense de Visual Studio.

IntelliSense mostrando función EscalaGrises

EJEMPLO BÁSICO DE APLICACIÓN
En este apartado se intentará iniciar a crear una pequeña aplicación para ver el funcionamiento básico de cómo crear un proyecto valiéndose de las funcionalidades de la biblioteca de clases desarrollada. El resultado de la aplicación (que podéis descargar desde aquí), será el siguiente:

Aplicación con ClaseImagenes.dll

Como puede observarse, el programa tiene varios botones para aplicar diferentes transformaciones, además de una imagen general (en la parte inferior derecha) y opciones para hacer/deshacer las diferentes transformaciones y abrir/guardar imágenes.
Una vez creado el formulario con los botones, se va a empezar a mostrar el código fuente. Como se había indicado anteriormente, en primer lugar se debe agregar la biblioteca dll, y después hacer la sentencia Imports.
Imports ClaseImagenes.Apolo
El siguiente paso será crear un objeto para poder gestionar todos los miembros de la clase.
'Se declara un objeto que se utilizará en todo el programa
Dim objetoTratamiento As New TratamientoImagenes
hora se va a mostrar el código fuente de los diferentes botones.
'BOTÓN ABRIR IMAGEN
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
    'Asignamos a una bitmap el resultado de la imagen abierta
    Dim bmpAbierto As Bitmap = objetoTratamiento.abrirImagen()
    'Si se ha seleccionado una imagen (no está vacío), se asigna al Picturebox
    If bmpAbierto IsNot Nothing Then
        PictureBox1.Image = bmpAbierto
    End If
End Sub

'BOTÓN GUARDAR IMAGEN
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    'Mostramos cuadro de diálogo para guardar
    objetoTratamiento.guardarcomo(PictureBox1.Image, 4)
End Sub

'BOTÓN IMAGEN ATRÁS (DESHACER)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'Se selecciona la imagen anterior
    PictureBox1.Image = objetoTratamiento.ListadoImagenesAtras
End Sub

'BOTÓN IMAGEN ADELANTE (REHACER)
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    'Se selecciona la imagen siguiente
    PictureBox1.Image = objetoTratamiento.ListadoImagenesAdelante
End Sub

'BOTÓN DE IMAGEN ORIGINAL
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
   'Carga la última imagen abierta como original
   PictureBox1.Image = objetoTratamiento.ImagenOriginalGuardada
End Sub

'BOTÓN BLANCO Y NEGRO
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Transformamos la imagen a blanco y negro (umbral 128)
    PictureBox1.Image = objetoTratamiento.BlancoNegro(bmp, 128)
End Sub

'BOTÓN ESCALA DE GRISES
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Transformamos la imagen a escala de grises
    PictureBox1.Image = objetoTratamiento.EscalaGrises(bmp)
End Sub

'BOTÓN A TONOS SEPIA
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Transformamos la imagen a tonos sepia
    PictureBox1.Image = objetoTratamiento.sepia(bmp)
End Sub

'BOTÓN INVERTIR COLORES
Private Sub Button10_Click(sender As Object, e As EventArgs) Handles Button10.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Invertimos los colores de la imagen (para los tres canales RGB)
    PictureBox1.Image = objetoTratamiento.Invertir(bmp, True, True, True)
End Sub

'BOTÓN APLICAR MARCO
Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Se envuelve la imagen en un marco (el número 3)
    PictureBox1.Image = objetoTratamiento.marco(bmp, 2)
End Sub

'BOTÓN DETECTAR CONTORNOS
Private Sub Button14_Click(sender As Object, e As EventArgs) Handles Button14.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Se calculan los contornos
    PictureBox1.Image = objetoTratamiento.contornos(bmp, 15, 100, 100, 100)
End Sub

'BOTÓN DE DISTORSIÓN
Private Sub Button13_Click(sender As Object, e As EventArgs) Handles Button13.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Se calculan los contornos
    PictureBox1.Image = objetoTratamiento.Distorsion(bmp, NumericUpDown1.Value)
End Sub

'BOTÓN PERÍMETRO (OPERACIÓN MOROFOLÓGICA)
Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Creamos un objeto que contiene elementos estructurales predefinidos
    Dim objetoEstructura As New TratamientoImagenes.ElementoEstructural
    'Se crea una matriz de dos dimensiones que alojará el elemento estructural y le damos un valor inicial
    Dim ElemenEstructural(,) As Integer = objetoEstructura.Cuadrado3x3

    Select Case ComboBox1.SelectedItem
        Case "Cuadrado 3x3"
            ElemenEstructural = objetoEstructura.Cuadrado3x3
        Case "Cuadrado 5x5"
            ElemenEstructural = objetoEstructura.Cuadrado5x5
        Case "Diamante 5x5"
            ElemenEstructural = objetoEstructura.Diamante5x5
    End Select
    'Transformamos el bitmap calculando el perímetro mediante una operación morfológica
    PictureBox1.Image = objetoTratamiento.MorfologicasPerimetroDilatOrigin(bmp, ElemenEstructural)
End Sub

'BOTÓN MÁSCARAS
Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click
    'Creamos un bitmap con la imagen actual
    Dim bmp As New Bitmap(PictureBox1.Image)
    'Creamos un objeto que contiene elementos estructurales predefinidos
    Dim objetoMascara As New TratamientoImagenes.Mascaras
    'Se crea una matriz de dos dimensiones que alojará la máscara y le damos un valor inicial
    Dim Mascara(,) As Double = objetoMascara.LineasVerticales

    Select Case ComboBox2.SelectedItem
       Case "Líneas verticales"
            Mascara = objetoMascara.LineasVerticales
       Case "Repujado"
            Mascara = objetoMascara.Repujado
       Case "Laplaciana"
            Mascara = objetoMascara.Laplaciana1
    End Select
    'Transformamos el bitmap operando a través de una máscara
    PictureBox1.Image = objetoTratamiento.mascara3x3RGB(bmp, Mascara)
End Sub
Se puede observar, que el código es muy sencillo, simplemente (para las transformaciones) se define el Bitmap que se enviará a la clase y los parámetros si los hubiese. Con respecto a las opciones de hacer/deshacer la sentencia es muy simple y es la propia clase quien gestiona todo. Un último detalle para poder gestionar el evento de la imagen de detalle que está en la parte inferior, primeramente se debe incluir al manejador en el load del formulario.
'INICIO DE FORMULARIO
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    'Asignamos el gestor que controle cuando sale imagen
    AddHandler objetoTratamiento.actualizaBMP, New ActualizamosImagen(AddressOf actualizarPicture)
End Sub
Una vez creado el manejador, se incluye un procedimiento que recibirá un parámetro como Bitmap y se asignará al Picturebox2, y así cuando se modifique (mediante la biblioteca ClaseImagenes) un Bitmap enviado, se mostrará también el cambio en el Picturebox2.
Sub actualizarPicture(ByVal bmp As Bitmap)
    'Asignamos al Picturebox2 cuando se detecta una transformación de la imagen
    PictureBox2.Image = bmp
End Sub
Como hemos visto todo el proceso es muy sencillo y en el ejemplo que se ha mostrado es sólo una pequeña parte. Si tenéis cualquier duda comentarlo. ¡Espero que os sirva de ayuda!
Descarga la biblioteca de clases ClaseImagenes.dll:

Descarga la aplicación de ejemplo:


Descarga la documentación técnica:
                                                                                                                                   

Más info en http://ocw.usal.es/ensenanzas-tecnicas/herramientas-informaticas-para-el-geoprocesado.

16 comentarios:

  1. Hola que tal me gustaria saber como hacer zoom en la imagen usando la biblioteca que presentas

    ResponderEliminar
    Respuestas
    1. Directamente no hay una función que lo haga, pero si por ejemplo tienes un formulario con dos Picturebox (como en el ejemplo de la entrada) y tres botones, puedes hacer esto:
      Dim objetoTratamiento As New ClaseImagenes.Apolo.TratamientoImagenes()
      'Zoom Más
      Private Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
      objetoTratamiento.Zoom += 0.1
      Dim bmp As New Bitmap(PictureBox2.Image)
      Dim bmp2 As New Bitmap(bmp, bmp.Width * objetoTratamiento.Zoom, bmp.Height * objetoTratamiento.Zoom)
      pictureBox1.Image = bmp2
      End Sub

      'Zoom menos
      Private Sub button2_Click(sender As Object, e As EventArgs) Handles button2.Click
      If objetoTratamiento.Zoom - 0.1 > 0 Then
      objetoTratamiento.Zoom -= 0.1
      Dim bmp As New Bitmap(PictureBox2.Image)
      Dim bmp2 As New Bitmap(bmp, bmp.Width * objetoTratamiento.Zoom, bmp.Height * objetoTratamiento.Zoom)
      pictureBox1.Image = bmp2
      Else
      MessageBox.Show("Zoom mínimo superado.", "Apolo", MessageBoxButtons.OK, MessageBoxIcon.Information)
      End If
      End Sub

      'Deshacer zoom
      Private Sub button3_Click(sender As Object, e As EventArgs) Handles button3.Click
      objetoTratamiento.Zoom = 1
      Dim bmp As New Bitmap(PictureBox2.Image)
      Dim bmp2 As New Bitmap(bmp, bmp.Width * objetoTratamiento.Zoom, bmp.Height * objetoTratamiento.Zoom)
      pictureBox1.Image = bmp2
      End Sub


      También puedes echarle un vistazo a esta entrada: http://algoimagen.blogspot.com.es/2013/02/zoom-interactivo-en-picturebox.html

      Eliminar
    2. Mira, aquí tienes un ejemplo:
      http://sdrv.ms/10YmTqi

      Eliminar
    3. Gracias por tu respuesta, vi la entrada de zoom interactivo, sin embargo me gustaria hacer el zoom dentro del mismo PictureBox, Casi tal cual hace el vizor de imagenes de windows jeje. Tu crees que sustituyendo la imagen en el picturebox pueda hacerse?

      Eliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  3. como podria hacer para capturar el color mas relevante en un pixel por ejemlo si capturo una foto y la foto el color mas relevante es el rojo que me muestre por pantalla el color mas relevante de toda la imagen
    agredesco si me puede colaboar es urgente

    ResponderEliminar
  4. Hola. excelentes trabajos...
    he descargado la documentación (DocumentationTecnica.chm) y pueda observar (ver) el árbol a la izquierda, pero no puedo leer el documento, No me aparece nada a la derecha.....

    ResponderEliminar
    Respuestas
    1. Cierto. Tienes razón, no funciona. Ya he actualizado el archivo de la entrada.
      Lo puedes descargar desde aquí.
      http://sdrv.ms/19DGXm5
      Un saludo

      Eliminar
  5. Hola luis algun correo necesito poder enviar un problema q tengo si me puedes ayudar
    Saludos

    ResponderEliminar
    Respuestas
    1. Pues hablar por twitter, google +... mira los enlaces de la derecha
      Un saludo

      Eliminar
  6. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  7. DISCULPA COMO PUEDO HACER PARA QUE UNA IMAGEN QUE YA TENGO CARGADA EN UN PICTUREBOX LA PUEDA INCREMENTAR Y DECREMANTAR EN LA ESCALA DE GRISES CON LA AYUDA DE 2 BOTONES(+1, -1)

    ResponderEliminar
  8. DISCULPA COMO PUEDO HACER PARA QUE UNA IMAGEN QUE YA TENGO CARGADA EN UN PICTUREBOX LA PUEDA INCREMENTAR Y DECREMANTAR EN LA ESCALA DE GRISES CON LA AYUDA DE 2 BOTONES(+1, -1).
    LUIS CONTESTAME PORFAVOR, NECESITO HACERLO PARA MAÑANA :´(

    ResponderEliminar
  9. hola, como harias para hacer mediciones dentro de una imagen, como el largo y ancho de una puerta o ventana dentro de foto.

    ResponderEliminar
  10. Como haria para que una imagen con cualquier color de fondo y letras con diferentes colores, solo me apararezcan las letras en negro y el fondo solamente en blanco. Es decir para poder hacer OCR con la imagen y obtener solo el texto.

    ResponderEliminar
  11. Hola me gustaría saber si podrías ayudarme a hacer un programa similar pero para segmentar imágenes usando texturas

    ResponderEliminar