lunes, 25 de marzo de 2013

Eliminar ojos rojos de una fotografía. Tratamiento de imágenes. Parte XI.

En esta entrada vamos a exponer un sencillo método para eliminar los ojos rojos en un fotografía. El método no es completamente automático, es decir, no va a detectar la posición de los ojos sino que el usuario tiene que dar las coordenadas y el radio del círculo de los ojos.
Abrimos un nuevo proyecto en Visual Studio y creamos el siguiente formulario.

Formulario para detectar ojos rojos


Como podemos observar está compuesto de varios Textbox donde se introducirán los datos, un Picturebox donde estará la imagen, 3 botones y abajo una barra StatusStrip al que se le ha añadido un ToolStripStatusLabel que será donde se muestren las coordenadas del puntero con respecto al Picturebox. Una vez tenemos el formulario creado, vamos a explicar el proceso para detectar y corregir los ojos rojos.
La función que corrige los ojos rojos es la siguiente:

Private Function EliminarOjosRojos(ByVal bmp As Bitmap, ByVal CentroOjo As Point, ByVal radioOjo As Integer, Optional valorMinimo As Double = 1.5)
        Dim bmpCirculo As New Bitmap(bmp)
        Dim bmpCopia As New Bitmap(bmp)

        Dim gr As Graphics = Graphics.FromImage(bmpCirculo)

        'Le damos un color poco problable para un ojo (amarillo puro) ya que luego evaluaremos el cuadrado circunscrito a la circunferencia
        Dim relleno As Brush = New SolidBrush(Color.FromArgb(255, 255, 255, 0))
        gr.FillEllipse(relleno, CentroOjo.X - radioOjo, CentroOjo.Y - radioOjo, radioOjo * 2, radioOjo * 2)
        Dim bmpPintado As New Bitmap(bmpCirculo) 'Almacenamos una copia de la imagen con la primera línea

        Dim rojo, verde, azul As Integer
        'Recorremos el cuadrado circunscrito a la circunferencia
        For i = CentroOjo.X - (radioOjo - 1) To CentroOjo.X + (radioOjo + 1)
            For j = CentroOjo.Y - (radioOjo - 1) To CentroOjo.Y + (radioOjo + 1)
                'Si el valor es amarillo (es decir, es el círculo que creamos)
                If bmpPintado.GetPixel(i, j) = (Color.FromArgb(255, 255, 255, 0)) Then
                    Dim intensidadRojo As Double
                    verde = bmp.GetPixel(i, j).G
                    azul = bmp.GetPixel(i, j).B
                    rojo = bmp.GetPixel(i, j).R
                    intensidadRojo = (rojo / ((verde + azul) / 2))
                    'Hacemos la comprobación de que sea un ojo rojo (el valor más adecuado por norma general es 1.5)
                    If intensidadRojo > valorMinimo Then
                        'Creamos el valor rojo a partir del verde y azul
                        rojo = (verde + azul) / 2
                        bmpCopia.SetPixel(i, j, Color.FromArgb(rojo, verde, azul))
                    End If

                End If
            Next
        Next
        Return bmpCopia
End Function

A esta función se le envía la imagen original (en formato Bitmap), el centro del ojo (coordenadas X e Y), el radio del ojo y opcionalmente el valor mínimo. Lo que hará será crear un círculo de color amarillo con los datos recibidos y dentro del cuadrado circunscrito a ese círculo evaluará los píxeles y, si son amarillos (es decir, están dentro del círculo), entonces evalúa el valor original de ese píxel. Si ese valor original está dentro del mínimo que se le pasa a la función (por defecto es 1.5) entones actuará calculando el nuevo valor del color rojo como la media de los canales verde y azul.
Con respecto al parámetro valor mínimo, lo que hace es calcular, para cada píxel analizado, la siguiente operación, (rojo / ((verde + azul) / 2)), y si es superior el resultado al valor mínimo (por defecto 1.5), entonces quiere decir que vamos a aplicar la modificación al píxel.
Como observamos la función no es perfecta pero es una sencilla forma de eliminar los ojos rojos.
Adicionalmente, para mostrar las coordenadas del cursor dentro del Picturebox utilizaremos el evento MouseMove asociado al propio PictureBox.

 Private Sub PictureBox1_MouseMove1(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        ToolStripStatusLabel1.Text = "(" & e.Location.X & "," & e.Location.Y & ") px"
 End Sub

El resultado tras aplicar la función es el siguiente:

Imagen con ojos rojos corregidos


Para descargar el código fuente, haz clic en la imagen que hay debajo:

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

No hay comentarios:

Publicar un comentario