martes, 27 de marzo de 2012

Tratamiento de imágenes(Parte I)

Una vez sabemos cómo cargar la imagen y almacenarla en un PictureBox (si no lo sabes, pulsa aquí), ya estamos preparado para lo más interesante, realizar modificaciones en las imágenes.
Abrimos el proyecto anterior, que si recordamos contenía un Panel, un PictureBox, un OpenFileDialog y un botón.
El siguiente paso será, al principio del código, crear una variable en la que se puede guardar los niveles digitales de la imagen:


Public Niveles(,) As System.Drawing.Color 'Almacenará los niveles digitales de la imagen

Agregamos un botón más (denominado cargar) al formulario, y le asignamos el siguiente código:

'Este primer bloque, guarda los niveles digitales de la imagen en la variable Niveles
 Dim i, j As Long

    ReDim  Niveles (PictureBox1.Image.Width - 1, PictureBox1.Image.Height - 1)  'Asignamos a la matriz las dimensiones de la imagen -1 *
        Dim bmp As New Bitmap(PictureBox1.Image)  'Creamos un objeto de la clase Bitmap
        For i = 0 To PictureBox1.Image.Width - 1 'Recorremos la matriz a lo ancho
            For j = 0 To PictureBox1.Image.Height - 1 'Recorremos la matriz a lo largo
                 Niveles (i, j) = bmp.GetPixel(i, j) 'Con el método GetPixel, asignamos para cada celda de la matriz el color con sus valores RGB.
            Next
        Next

*El -1 se debe a que la matriz empieza en 0 en vez de en 1, por lo tanto, si la imagen tiene 200 píxeles de ancho, la matriz deberá tener de ancho 199.


Con todo esto, ya hemos conseguido cargar la matriz (con sus niveles digitales) en nuestra variable Niveles. Podemos compilar y ejecutar (pulsar F5), primeramente abrimos la imagen seleccionada desde archivo, y posteriormente pulsamos en el botón Cargar. A priori, parece que no hace nada, pero está cargando, para cada celda de la matriz (Niveles), la combinación RGB de cada píxel.
No obstante, si queremos hacer la interfaz menos cargada y más amigable para el usuario, sería conveniente que al cargar la imagen directamente se cargue también la matriz.

Una vez tenemos la matriz cargada, ya podemos pintarla en un PictureBox, pero además de pintarla, vamos a hacer una pequeña modificación sobre ella. El código para poder pintar esa matriz es el siguiente:

Dim i, j As Long
        Dim bmp As New Bitmap(Niveles.GetUpperBound(0) + 1, Niveles.GetUpperBound(1) + 1) 'Utilizamos el método GetUpperBound para dimesionar el nuevo objeto Bitmap
        Dim img As Image 'Creamos una variable image
        img = CType(bmp, Image) 'Realizamos la conversión
        PictureBox1.Image = img
        Panel1.AutoScrollMinSize = PictureBox1.Image.Size
        PictureBox1.Refresh()
        For i = 0 To Niveles.GetUpperBound(0) 'Recorremos la matriz
            For j = 0 To Niveles.GetUpperBound(1)
                bmp.SetPixel(i, j, Niveles(i, j))  'Asignamos el valor de Niveles al bmp
            Next
        Next
        img = CType(bmp, Image) 'Realizamos de nuevo conversión
        PictureBox1.Image = img 'Pintamos en el PictureBox
        PictureBox1.Refresh() 'Refrescamos

Este bloque lo que hace es pintar la matriz, pero antes de pintarla, vamos a realizar una inversión de sus colores. Para ello, simplemente hay que restar 255 menos el color correspondiente a la imagen.

Dim Rojo, Verde, Azul As Byte 'Declaramos tres variables que almacenarán los colores
       For i = 0 To Niveles.GetUpperBound(0)  'Recorremos la matriz
            For j = 0 To Niveles.GetUpperBound(1)
                Rojo = 255 - (Niveles(i, j).R) 'Realizamos la inversión de los colores
                Verde = 255 - (Niveles(i, j).G) 'Realizamos la inversión de los colores
                Azul = 255 - (Niveles(i, j).B) 'Realizamos la inversión de los colores
                bmp.SetPixel(i, j, Color.FromArgb(Rojo, Verde, Azul)) 'Asignamos a bmp los colores invertidos
            Next
      Next

Esta última porción de código nos daría error, puesto que no está declarado bmp. Para solucionarlo y simplificar el código, vamos a unir la creación del bmp, la inversión y el dibujarlo sobre el PictureBox:

        Dim i, j As Long
        Dim bmp As New Bitmap(Niveles.GetUpperBound(0) + 1, Niveles.GetUpperBound(1) + 1)
        Dim img As Image
        img = CType(bmp, Image)
       
        Dim Rojo, Verde, Azul As Byte 'Declaramos tres variables que almacenarán los colores
        For i = 0 To Niveles.GetUpperBound(0)  'Recorremos la matriz
            For j = 0 To Niveles.GetUpperBound(1)
                Rojo = 255 - (Niveles(i, j).R)
                Verde = 255 - (Niveles(i, j).G)
                Azul = 255 - (Niveles(i, j).B)
                bmp.SetPixel(i, j, Color.FromArgb(Rojo, Verde, Azul))
            Next
        Next
        PictureBox1.Image = img
        Panel1.AutoScrollMinSize = PictureBox1.Image.Size
        PictureBox1.Refresh()

Hacemos un pequeño repaso:
-Abrimos la imagen desde archivo.
-Cargamos la imagen en la matriz Niveles.
-Creamos el objeto bmp .
-Invertimos los colores de Niveles.
-Asignamos los niveles a bmp.
-Dibujamos.

El resultado sería el siguiente:

Si quieres descargar el código fuente, pulsa aquí.
Para más información sobre Bitmap, visita msdn online.

4 comentarios:

  1. Gracias por la aportación :)

    ResponderEliminar
  2. Tengo una duda
    podrias explicarme la siguiente parte
    Dim bmp As New Bitmap(Niveles.GetUpperBound(0) + 1, Niveles.GetUpperBound(1) + 1)

    tambien, me gustaria saber porque en un es cero y en el otro en un 1

    ResponderEliminar
    Respuestas
    1. Al parecer GetUpperBound(0), se refiere a la dimensión en el eje X, y el GetUpperBound(1) al eje Y, es decir a la segunda dimensión de la matriz (XY). Esto daría las dimensiones actuales de ancho y alto de la imagen. El +1 es por que la matriz es base cero.

      Eliminar