Códigos Cadena

Una manera para encontrar los contornos, es utilizar el algoritmo de códigos de cadena. Los códigos de cadena tienen como objetivo  representar un contorno por medio de una sucesión conexa de segmentos de longitud y dirección especificadas. La conexión de los segmentos se lleva a cabo en entornos de 4 vecinos o de 8 vecinos. Cuando se usa un entorno de 4 vecinos tendremos cuatro orientaciones para los segmentos, como se muestra en la siguiente figura,  y utilizaremos los números 0,1,2 y 3 para especificar la orientación de los segmentos. Si se usa un entorno de 8 vecinos tendremos 8 orientaciones posibles (ver siguiente figura).



El código de cadena genera una secuencia de números que representan las orientaciones de los segmentos conectados consecutivamente, partiendo de un punto del contorno y siguiendo el sentido de las agujas del reloj. Por ejemplo, la cadena 0033333323221211101101 representa el contorno  del objeto de la figura  posterior cuando empezamos por el píxel superior izquierdo del contorno. Aunque depende del punto de partida, ello no supone un problema pues se puede considerar el código como una lista circular en el caso de contornos cerrados.

En nuestro programa se intercambian la orientación para el contorno 4 en la siguiente manera:

     /**
   *  2
   * 1_3
   *  0
   */

Y el método encargado de buscar la dirección e ir girando para buscar los puntos vecinos es: 


  private Punto getProxVec4(int x, int y){
    int startDirection = (directCuat+3) % 4;
    int i = 0;
    Punto d = null;
    while(i < 3){
      d = getPuntoVecino4(x, y, startDirection); 
      if(d != null){
        directCuat = startDirection;
        break;
      }
      startDirection = mod ((startDirection +1), 4); 
      i++;
    }
    return d;
  }

Recibe como argumentos la posición del pixel y regresa una variable de tipo Punto, que hace referencia a una posición en la imagen. El método encargado de encontrar el punto vecino de acuerdo a la dirección que se le proporciona se muestra a continuación:


private Punto getPuntoVecino4(int x, int y, int dir) {
 switch(dir) {
  case 0:
     return(enLimite(x+1,y)&&esPixel(x+1,y))?
            new Punto(x+1,y):null;
  case 1:
     return(enLimite(x,y-1)&&esPixel(x,y-1))?
            new Punto(x,y-1):null;
  case 2:
     return(enLimite(x-1,y)&&esPixel(x-1,y))?
            new Punto(x-1,y):null;
  case 3:
     return(enLimite(x,y+1)&&esPixel(x,y+1))?
            new Punto(x,y+1):null;
  default:
  return null;
 }
}

El método enLimite, se encarga de verificar que solamente abarque los puntos dentro de la imagen, mientras que el método esPixel, verifica que el elemento de la matriz corresponda a valores permitidos. Se muestran a continuación los dos métodos:


private boolean enLimite(int x, int y){
   if((x >= 0 && x < height) && (y >= 0 && y < width)) {
       return true;
   } else {
       return false;
   }
}  
    
private boolean esPixel(int x, int y){
   if(imagen[x][y] > 0) {
       return true;
   } else {
       return false;
   }
}


En caso de que la dirección corresponda a un valor correcto (dentro de la matriz o sea un pixel) regresará una variable de tipo Punto, con la posición en la cual corresponde al borde.

La trayectoria del contorno es obtenida con el método inicio4. Este método empieza con el primer pixel de la imagen, el cual se obtiene barriendo la imagen desde la primera línea de izquierda a derecha; y regresa una lista de valores de tipo Punto que representa la posición del contorno de la imagen.

public List<Punto> inicio4(int x, int y) {
  List<Punto> ruta = new ArrayList<Punto>();
  Punto firstCell  = new Punto(x, y);
  Punto d1         = firstCell;
  ruta.add(new Punto(x,y)); //Add cell1   
  Punto secondCell = getProxVec4(x, y);
  Punto  d2        = secondCell;    
  do{
    x = (int) d2.getX();
    y = (int) d2.getY();         
    d1 = d2;
    d2 = getProxVec4(x, y);
    ruta.add(new Punto(x,y));  
  }while(!d1.equals(firstCell)&&
         !d2.equals(secondCell)&&d2!=null);
  ruta.remove(0);    
  return ruta;
}

En la siguiente figura se muestra un resultado de la aplicación del algoritmo de códigos de cadena.



De manera análoga funcionan los métodos para calcular el contorno 8, el cual fue también modificado de la siguiente forma:

   /**
   * 345
   * 2_6
   * 107
   */

Si te fue útil esta información, recuerda ponerme como referencia para tus trabajos o proyectos.


Referencias

·         Burger Wilhelm and Burge Mark, Digital Image Processing, Primera Edición, Editorial Springer, 2008.

Comentarios

  1. excelente articulos sobre los codigos de cadena, me gustaria saber más sobre el codigo de 8N, tienes algun dato de contacto?

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Los diagramas de Voronoi y la triangulación Delaunay

Etiquetado de componentes conectadas