sábado, 4 de mayo de 2013

Histograma acumulado. Tratamiento de imágenes. Parte XIV.

El histograma acumulado de una imagen no es más que contar, para cada canal RGB, el número de píxeles que hay de cada componente. Por ejemplo, para el canal rojo, el número de píxeles que tienen valor 255.
Estos histogramas nos proveen de mucha información sobre la imagen y cómo poder mejorarla, por ejemplo, aumentando el ancho del histograma (aumentando el contraste). Y en esta entrada, vamos a ver cómo podemos hacerlos con Visual Basic. La forma de hacerlos será mediante una función denominada histogramaAcumulado la cual nos devolverá una matriz de 2 dimensiones que almacenará el histograma acumulado de los canales RGB.

Public Function histogramaAcumulado(ByVal bmp As Bitmap) As Integer(,)
    Dim Rojo, Verde, Azul As Byte 'Declaramos tres variables que almacenarán los colores
    Dim matrizAcumulada(2, 255) As Integer
    For i = 0 To bmp.Width - 1 'Recorremos la matriz
        For j = 0 To bmp.Height - 1
            Rojo = bmp.GetPixel(i, j).R 'Asignamos el color
            Verde = bmp.GetPixel(i, j).G
            Azul = bmp.GetPixel(i, j).B
            'ACumulamos los valores. 
            matrizAcumulada(0, Rojo) += 1
            matrizAcumulada(1, Verde) += 1
            matrizAcumulada(2, Azul) += 1
        Next
    Next
    Return matrizAcumulada
End Function

La función primeramente almacena en tres variables (rojo, verde, azul) el color de cada píxel, y después, va acumulando los valores en la matriz de retorno. La matriz de retorno tiene dos dimensiones y el histograma acumulado está en el siguiente rango:
  • Para el canal rojo de matrizAcumulada(0,0) a matrizAcumulada(0,255).
  • Para el canal verde de matrizAcumulada(1,0) a matrizAcumulada(1,255).
  • Para el canal azul de matrizAcumulada(2,0) a matrizAcumulada(2,255).
El siguiente paso, será crear un control Chart al que le añadiremos una serie denominada Histograma, y el tipo de chart será SplineArea. El resultado del formulario sería algo así:

Formulario con histograma

Ahora vamos a añadir el código fuente asociado a los tres botones y al load del formulario.

Dim histoAcumulado As Integer(,) 'Variable que almacenará los histogramas
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    'Cargamos los histogramas
    Dim bmp As New Bitmap(PictureBox1.Image)
    histoAcumulado = histogramaAcumulado(bmp)
    'Ejecutamos el botón del histograma rojo
    Button1_Click(sender, e)
End Sub
     
'Histograma rojo
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'Borramos el posible contenido del chart
    Chart1.Series("Histograma").Points.Clear()
    'Los ponesmos del colores correspondiente
    Chart1.Series("Histograma").Color = Color.Red
    For i = 0 To 255
        Chart1.Series("Histograma").Points.AddXY(i + 1, histoAcumulado(0, i))
    Next
End Sub
'Histograma verde
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    'Borramos el posible contenido del chart
    Chart1.Series("Histograma").Points.Clear()
    Chart1.Series("Histograma").Color = Color.Green
    For i = 0 To 255
        Chart1.Series("Histograma").Points.AddXY(i + 1, histoAcumulado(1, i))
    Next
End Sub
'Histograma azul
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    'Borramos el posible contenido del chart
    Chart1.Series("Histograma").Points.Clear()
    Chart1.Series("Histograma").Color = Color.Blue
    For i = 0 To 255
        Chart1.Series("Histograma").Points.AddXY(i + 1, histoAcumulado(2, i))
    Next
End Sub

Lo que hacemos es llamar a la función en el load del formulario y después, en función del botón pulsado, recorrer la variable que contiene el histograma (histoAcumulado) y dibujarlo en el Chart.
Puedes descargar el código fuente aquí:

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

4 comentarios:

  1. Hola muy bueno tus aportes he aprendido mucho,tengo una consulta.
    Estoy haciendo una funcion en la cual detecta los colores y me dice la cantidad de cada uno.
    El problema que tengo que hay imagenes que tengo por ejemplo un rojo y otro casi igual pero me lo pone como colores distintos.
    Como puedo simplificar los colores.
    Saludos Gracias

    ResponderEliminar
    Respuestas
    1. Hola jona. Lo que quieres hacer se llama segmentación. Hay muchas formas, unas más fáciles y otras más complejas. Un ejemplo fácil de segmentación es el binarizar una imagen (blanco y negro), o pasarla a escala de grises.
      Espero que te sirva de ayuda.
      Un saludo.

      Eliminar
    2. Gracias por responder, estoy haciendo una funcion en la cual detecta los colores que hay y me dice la cantidad que tiene de superficie de cada color en una imagen,pero si lo paso a escala de grises,como se a cual color corresponde.
      Gracias

      Eliminar
  2. Hola muchas gracias por tus aportes, mi problema es que me marca herror en esta parte.

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim bmp As New Bitmap(PictureBox1.Image)

    Me dice: No se controló NullReferenceException.

    ResponderEliminar