Inicio » Programación » Detectando «bordes»

Detectando «bordes»

Buenas tardes.

Sé que habéis llegado hasta aquí pensando en detectar otro tipo de «bordes», pero esos que pensáis no hace falta detectarlos de ninguna manera ya que se dejan ver por si solos.

Hoy os voy a hablar de otro tipo de «bordes». El título podría ser «detección de bordes» o «detección de contornos».

Evidentemente hay miles de herramientas con miles de filtros que realizan ésta tarea muchísimo mejor de lo que yo lo voy a hacer aquí, pero ya sabéis que ésto trata de «lo entendí, y fui capaz de hacerlo por mí mismo, que sabe mucho mejor…» Al final del artículo tenéis tanto el código fuente como el link para descargar el ejecutable.

Por trabajo, me tocó investigar sobre detección de contornos en una imagen para ver cómo se podría realizar un reconocimiento de caracteres o cosas similares, pero autónomamente. Es decir, sin depender de un software de tercero con el que aplicar los filtros y tratar las imágenes, si no desarrollar un software que aplicase los filtros necesarios y extrajese la información necesaria de la imagen por si sólo.

Buscando información en Internet, encontraréis que si filtros laplacianos, que si matriz de Sobel vertical, matriz de Sobel horizontal… y unas explicaciones con fórmulas matemáticas, gráficos y demás parafernalia que al final no es tan complicada de entender.

Para mis pruebas yo me decidí por la matriz de Sobel. Lo que hace básicamente es tener en cuenta los 8 píxeles que rodean al píxel que estamos analizando en cada momento para determinar un «gradiente» y, dependiendo del umbral que le hayamos marcado, decidir si lo marca como «contorno» o no. Al final, lo que tendremos será una imágen en la que tendremos píxeles a blanco y píxeles a negro donde esté el contorno o borde y de la que eliminaremos el resto de la información.

Dependiendo del «umbral» que marquemos, la imagen tendrá unos contornos finos y definidos o gruesos y más difuminados. El resultado final dependerá de dicho umbral que decidamos aplicar.

He realizado una aplicación en visual basic (visual studio 2010) para demostrar el funcionamiento de dicha matriz.

El funcionamiento es sencillo:

  1. Con el botón «abrir imagen» seleccionamos la imagen de la que deseamos extraer los contornos.
  2. Seleccionamos un umbral con el trackbar (entre 0 y 255 que son las intensidades que podemos encontrar para un pixel).
  3. Por último pulsamos sobre «aplicar Sobel» y veremos aparecer el resultado en la ventana adjunta.
  4. Podremos guardar la imagen resultante pulsando sobre «Guardar».

Aquí os presento la diferencia entre aplicar un umbral bajo o uno alto a una matrícula, por ejemplo.

Umbral Bajo:

filtro_bajo

Umbral Alto:

filtro_alto

Como se puede apreciar, con un umbral alto se obtienen unos contornos muy claros y definidos (también se debe al alto contraste entre los caracteres de la matrícula y el fondo).

Os dejo otro ejemplo más aplicado sobre la imagen de un coche.

coche_sobel

Os dejo el código fuente del programa para que veáis lo sencillo que puede ser crear nuestro propio filtro detector de contornos o bordes.

Aquí el enlace al ejecutable.

Saludos y hasta la próxima.

Imports System.drawing

Public Class Form1

Dim contador
Dim horizontal()

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    OpenFileDialog1.ShowDialog()
    If OpenFileDialog1.FileName <> "" Then
        PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName)
        ListBox1.Items.Clear()
    End If
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    ListBox1.Items.Clear()
    Dim vectorx(,) = {{1, 0, -1}, {2, 0, -2}, {1, 0, -1}}
    Dim vectory(,) = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}}
    Dim img1 As Bitmap
    img1 = New Bitmap(PictureBox1.Image)
    Dim img2 As New Bitmap(img1.Width, img1.Height, Imaging.PixelFormat.Format32bppArgb)
    ReDim horizontal(img2.Width - 1)
    For i As Integer = 0 To UBound(horizontal) - 1
        horizontal(i) = 0
    Next

    For y As Integer = 0 To img1.Height - 1
        contador = 0
        For x As Integer = 0 To img1.Width - 1
            Dim gradX As Single = 0
            Dim gradY As Single = 0
            Dim grad As Single = 0

            If x = 0 Or y = 0 Or x = img1.Width - 1 Or y = img1.Height - 1 Then
                grad = 0
            Else
                For i As Integer = -1 To 1
                    For j As Integer = -1 To 1
                        Dim p As Color = img1.GetPixel(x + i, y + j)
                        Dim intensity As Single = 0.333F * (CInt(p.R) + p.G + p.B)
                        gradX += intensity * vectorx(i + 1, j + 1)
                        gradY += intensity * vectory(i + 1, j + 1)
                    Next
                Next
                grad = (Math.Abs(gradX) + Math.Abs(gradY))
            End If
            grad = Math.Max(0, grad)
            grad = Math.Min(255, grad)
            If grad >= TrackBar1.Value Then
                img2.SetPixel(x, y, Color.Black)
                contador += 1
                horizontal(x) = horizontal(x) + 1
            End If
        Next
        PictureBox2.Image = img2
        PictureBox2.Refresh()
        ListBox1.Items.Add(contador)
    Next
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    SaveFileDialog1.ShowDialog()
    If SaveFileDialog1.FileName <> "" Then
        PictureBox2.Image.Save(SaveFileDialog1.FileName)
    End If
End Sub

Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    TrackBar1.Value = 122
End Sub

End Class


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.