miércoles, 28 de marzo de 2012

Tratamiento de imágenes (Parte II)

Tras la primera parte de tratamiento digital de imágenes bit a bit, en la que se ha desarrollado el sistema para cargar/dibujar la matriz, ahora vamos a ver algunos ejemplos en los que modificamos los valores de los píxeles.
Partimos del proyecto empezado y vamos a realizar algunas modificaciones.
Primero, vamos a unificar la parte en la que abrimos la imagen y cargamos la matriz, para ello asociamos, al botón de abrir, el siguiente código:

  With OpenFileDialog1 'Con esto conseguimos que no sea obligatorio escribir OpenFileDialog1
            'Establecemos los filtros de las imágenes
            .Filter = "Ficheros BMP|*.bmp" & _
                      "|Ficheros GIF|*.gif" & _
                      "|Ficheros JPG o JPEG|*.jpg;*.jpeg" & _
                      "|Ficheros PNG|*.png" & _
                      "|Ficheros TIFF|*.tif"
            .FilterIndex = 3 'Hacemos que el predeterminado se el tercer filtro, es decir, JPG o JPEG
            If (.ShowDialog() = Windows.Forms.DialogResult.OK) Then 'Abrimos el cuadro de diálogo
                PictureBox1.Image = Image.FromFile(.FileName) 'Asignamos el archivo seleccionado al                      PictureBox
                Panel1.AutoScrollMinSize = PictureBox1.Image.Size 'Asignamos a las barras de desplazamiento del panel el tamaño de la imagen
                Panel1.AutoScroll = True 'Ponemos a True esta opción para que se muestren las barras de desplazamiento

            End If
        End With 'Ya no se asocia el punto a OpenFileDialog1

      If Not OpenFileDialog1.FileName = "OpenFileDialog1" Then 'Nos aseguramos de que se ha cargado una imagen
        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
    End if

Para hacer todo un poco más elegante, vamos a utilizar un control disponible en Visual Studio, denominado MenuStrip. Este control hace aparecer en la parte superior del formulario una barra de herramientas similiar a la que tienen infinitud de aplicaciones, como Microsoft Word. En esta barra se suelen poner múltiples opciones, como Archivo/Abrir, Archivo/cerrar, etc.


Asociamos el código anterior a la opción que pone abrir. Para ello, al igual que con un botón, hacemos doble clic donde pone Abrir, y pegamos el código.
Además, creamos otro apartado en el que ponga Modificaciones y debajo de él, vamos a ir generando las diferentes opciones.


Una vez realizado esto, creamos al principio del código una variable pública:
  Public Modificacion As String
Nos servirá para identificar las diferentes operaciones a realizar (inversión, escala de grises, ...)

Hacemos doble clic sobre Invertir y asociamos el siguiente código:

   Modificacion = "invertir" 'Asignamos el valor invertir a la variable modificación
   Call modificar(Modificacion)  'Llamamos al procedimiento modificar con el valor "invertir"

El procedimiento modificar lo crearemos más adelante. Realizamos esto con todas las opciones:
+Brillo
        Modificacion = "+brillo"
        Call modificar(Modificacion)

-Brillo
        Modificacion = "-brillo"
        Call modificar(Modificacion)

Blanco y negro
        Modificacion = "b/n"
        Call modificar(Modificacion)

Escala de grises
        Modificacion = "grises"
        Call modificar(Modificacion)

Filtro rojo
        Modificacion = "rojo"
        Call modificar(Modificacion)

Filtro verde
        Modificacion = "verde"
        Call modificar(Modificacion)

Filtro azul
        Modificacion = "azul"
        Call modificar(Modificacion)

El siguiente paso es crear procedimiento modificar. El código es el siguiente:

 Sub modificar(ByRef tipo_modificacion)
        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) 'Recorremos la matriz
                Select Case tipo_modificacion  'Seleccionamos entre las diferentes modificaciones
                    Case "invertir"
                        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

                    Case "+brillo"
                        Dim AuxiliarR, AuxiliarG, AuxiliarB As Integer
                        'Realizamos primeramente el cálculo con variables auxiliares, para 
                        'que no se desborde las variables Rojo, Verde, Azul
                        AuxiliarR = (Niveles(i, j).R) + 20 'Aumentamos en 20 unidades el color rojo
                        AuxiliarG = (Niveles(i, j).G) + 20 'Aumentamos en 20 unidades el color verde
                        AuxiliarB = (Niveles(i, j).B) + 20 'Aumentamos en 20 unidades el color azul
                        'Comprobamos que no hay valores no válidos, es decir, mayores de 255
                        'Si hay valores mayores, los igualamos a 255
                        If AuxiliarR > 255 Then AuxiliarR = 255
                        If AuxiliarG > 255 Then AuxiliarG = 255
                        If AuxiliarB > 255 Then AuxiliarB = 255
                        Rojo = AuxiliarR
                        Verde = AuxiliarG
                        Azul = AuxiliarB                        
                        
                    Case "-brillo"
                        Dim AuxiliarR, AuxiliarG, AuxiliarB As Integer
                        'Realizamos primeramente el cálculo con variables auxiliares, para 
                        'que no se desborde las variables Rojo, Verde, Azul
                        AuxiliarR = (Niveles(i, j).R) - 20 'Disminuimos en 20 unidades el color rojo
                        AuxiliarG = (Niveles(i, j).G) - 20 'Disminuimos en 20 unidades el color verde
                        AuxiliarB = (Niveles(i, j).B) - 20 'Disminuimos en 20 unidades el color azul
                        'Comprobamos que no hay valores no válidos, es decir, menores de 0
                        'Si hay valores menores, los igualamos a 0
                        If AuxiliarR < 0 Then AuxiliarR = 0
                        If AuxiliarG < 0 Then AuxiliarG = 0
                        If AuxiliarB < 0 Then AuxiliarB = 0
                        Rojo = AuxiliarR
                        Verde = AuxiliarG
                        Azul = AuxiliarB

                    Case "b/n"
                        'Calculamos la media de los tres colores
                        Dim media As Double 'Variable para calcular la media
                        Dim rojoaux, verdeaux, azulaux As Double 'Variables auxiliares
                        'para que no se desborde
                        rojoaux = Niveles(i, j).R
                        verdeaux = Niveles(i, j).G
                        azulaux = Niveles(i, j).B

                        'Calculamos la media 
                        media = (rojoaux + verdeaux + azulaux) / 3
                        'En función de si el valor es mayor o menor de 128 (mitad aproximada
                        'de 255), lo convertimos en blanco o negro
                        If media >= 128 Then
                            Rojo = 255
                            Verde = 255
                            Azul = 255
                        Else
                            Rojo = 0
                            Verde = 0
                            Azul = 0
                        End If

                    Case "grises"
                        'Se calcula la media de los tres colores (de cada píxel), y se le asigna ese valores 
                        'a cada color
                        'Calculamos la media de los tres colores
                        Dim media As Double 'Variable para calcular la media
                        Dim rojoaux, verdeaux, azulaux As Double 'Variables auxiliares
                        'para que no se desborde
                        rojoaux = Niveles(i, j).R
                        verdeaux = Niveles(i, j).G
                        azulaux = Niveles(i, j).B

                        'Calculamos la media conviertiendo el resultado en un integer (CInt)
                        media = CInt((rojoaux + verdeaux + azulaux) / 3)
                        Rojo = media
                        Verde = media
                        Azul = media

                    Case "rojo"
                        'Calculamos la media, y asignamos el color al rojo y al resto 0
                        'Calculamos la media de los tres colores
                        Dim media As Double 'Variable para calcular la media
                        Dim rojoaux, verdeaux, azulaux As Double 'Variables auxiliares
                        'para que no se desborde
                        rojoaux = Niveles(i, j).R
                        verdeaux = Niveles(i, j).G
                        azulaux = Niveles(i, j).B
                        'Calculamos la media conviertiendo el resultado en un integer (CInt)
                        media = CInt((rojoaux + verdeaux + azulaux) / 3)
                        Rojo = media
                        Verde = 0
                        Azul = 0

                    Case "verde"
                        'Calculamos la media, y asignamos el color al verde y al resto 0
                        'Calculamos la media de los tres colores
                        Dim media As Double 'Variable para calcular la media
                        Dim rojoaux, verdeaux, azulaux As Double 'Variables auxiliares
                        'para que no se desborde
                        rojoaux = Niveles(i, j).R
                        verdeaux = Niveles(i, j).G
                        azulaux = Niveles(i, j).B
                        'Calculamos la media conviertiendo el resultado en un integer (CInt)
                        media = CInt((rojoaux + verdeaux + azulaux) / 3)
                        Rojo = 0
                        Verde = media
                        Azul = 0

                    Case "azul"
                        'Calculamos la media, y asignamos el color al verde y al resto 0
                        'Calculamos la media de los tres colores
                        Dim media As Double 'Variable para calcular la media
                        Dim rojoaux, verdeaux, azulaux As Double 'Variables auxiliares
                        'para que no se desborde
                        rojoaux = Niveles(i, j).R
                        verdeaux = Niveles(i, j).G
                        azulaux = Niveles(i, j).B
                        'Calculamos la media conviertiendo el resultado en un integer (CInt)
                        media = CInt((rojoaux + verdeaux + azulaux) / 3)
                        Rojo = 0
                        Verde = 0
                        Azul = media
                End Select
                bmp.SetPixel(i, j, Color.FromArgb(Rojo, Verde, Azul)) 'Asignamos a bmp los colores invertidos
            Next
        Next

        PictureBox1.Image = img
        Panel1.AutoScrollMinSize = PictureBox1.Image.Size
        PictureBox1.Refresh()
end sub

Compilamos y ejecutamos y podemos visualizar las modificaciones sobre la imagen.
Descarga el código fuente aquí.
Actualizado:
Si quisiésemos que las modificaciones se realizaran sobre la imagen que hay en el PictureBox en vez de la imagen original, al final del código anterior (antes del end sub), deberíamos poner:

  ReDim Niveles(PictureBox1.Image.Width - 1, PictureBox1.Image.Height - 1)  'Asignamos a la matriz las      dimensiones de la imagen -1 *
        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

5 comentarios:

  1. hola era por si me podiais ayudar, estoy intentando pasar de escala de grises a blanco y negro en el programa eclipse en idioma java

    ResponderEliminar
    Respuestas
    1. Fíjate en las entradas de tratamiento de imágenes con java --> http://algoimagen.blogspot.com.es/search/label/java?m=0

      Eliminar
  2. Hola me ayudas a dejar solo los verdes o rojos o azules para grisear el resto de pixeles que no sean de ese color

    ResponderEliminar