Listado de una función de convolución
Por Francisco Bernal Rosso.
 




 
/* Un par de definiciones para mejorar la legibilidad. */ 

#define c8b_elime(im,columna,fila) (*(im->entra_ime+fila)+columna) 
#define c8b_elims(im,columna,fila) (*(im->entra_ims+fila)+columna) 

typedef byte img8b; /* Componente de imagen de 8 bits. */ 

/* Definición de la estructura canal. */ 
typedef struct 
 { 
 int x; 
 int y; 
 img8b **entra_ime; /* Direcciones de las lineas. */ 
 img8b **entra_ims; 
 img8b *ime;   /* Imagen entrante. */ 
 img8b *ims;   /* Imagen saliente. */ 
 } canal8b; 
 

A continuación se muestra la realización de un filtro en lenguaje C sobre un canal de imagen del tipo descrito en "Descripción de un canal de imagen"

Como ya se ha comentado todas las funciones de esta biblioteca comienzan por el prefijo c8b_ que indica que se trata de funciones que trabajan sobre canales de 8 bits. También existen las correspondientes funciones c16b_ que lo hacen sobre canales de 16 bits.

La entrada al filtro es la función c8b_filtra  la llamada es c8b_filtro(*imagen,*mascara). Imagen es una estructura que,  fundamentalmente tiene la lísta de canales que forman la imagen real. Por su parte mascara es la máscara de convolución que se va a emplear. Esta función simplemente va tomando uno a uno los canales de la imagen y los va pasando por el filtro.
c8b_filtro llama a la función c8b_filtramcanal y como parámtros se le pasa la dirección del canal a filtrar y la de la máscara a emplear. c8b_filtrmcanal(*canal,*mascara). Esta función es la encargada de llamar al filtro verdadero. La imagen a filtrar (o sea, el canal) se divide en 9 partes. Como sabemos la máscara de filtrado es una matriz cuadrada peor en las zonas cercanas a los bordes de la imagen puede no ser posible efectuar el filtrado con la máscara completa. Por ejemplo, si tenemos una máscara de 3x3, solo se puede emplear en las zona de la imagen que está a más de 3 pixels del borde. Así la segunda línea superior solo se puede convolucionar con parte de la máscara. Pues bien l aimagen se divide en 9 partes correspondientes a los distintos casos en que nos podemos encontrar: Esquina superior izquierda, listón superior, esquina superior derecha, listón izquierdo, zona central donde vale toda la máscara, listón derecho, esquina inferior izquierda, listón inferior y esquina inferior derecha. El tamaño de cada zona depende del tamaño de la máscara. Así en el ejemplo de uan máscara de 3x3 la esquina superior izquierda será el cuadrado de 2x2 correspondiente y el liston inferior será la linea de 2 pixels de grosor que no llega hasta los bordes.
Cada una de estas nueve zonas tiene una función de filtrado optimizada para ella con lo que esperamos reducir tiempo de cálculo en las comparaciones.

El modelo de filtrado puede ser cualquiera de estas funciones pero prefiero emplear la función de filtrado central.c8b_filtrom_m.
 
Como ya se dijo en  "Descripción de un canal de imagen" la estructura c8b_canal contiene dos campos de imagen un dos listas de direcciones que apuntan al principio de cada una de las líneas de la imagen. De esta manera ahorramos tiempo en la determinación de la dirección correcta del pixel.
Hay dos imagenes ya que una es la original y la otra (la sombra) es donde se hacen los cálculos.
Para localizar un punto
#define c8b_elime(im,columna,fila) (*(im->entra_ime+fila)+columna)
 
 
c8b_filtrom_m(c,m) 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
  a las tablas de entrada para las dos im genes. */ 
float cpix; 
float *pm; 

pce=c->entra_ime; 
pcs=c->entra_ims; 

for (i=m->semilado;i<c->y-m->semilado;i++) { 
 for (j=m->semilado;j<c->x-m->semilado;j++) { 
  for (cpix=0,pm=m->ne,k=-m->semilado;k<m->semilado+1;k++) { 
   for (l=-m->semilado;l<m->semilado+1;l++,pm++) { 
    cpix+=*pm * (float) *(*(pce+i+k)+j+l); 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/(m->superficie)); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

/* ESQUINA SUPERIOR IZQUIERDA. */ 

c8b_filtrom_ai(c,m) /* Filtro arriba izquierda. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=0;i<m->semilado;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=0;j<m->semilado;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-i;k<m->semilado+1;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-j;l<m->semilado+1;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* LISTàN SUPERIOR. (Excepto lo contemplado 
     en arriba izquierda y arriba derecha. */ 

c8b_filtrom_a(c,m) /* Arriba. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=0;i<m->semilado;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=m->semilado;j<c->x-m->semilado;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-i;k<m->semilado+1;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-m->semilado;l<m->semilado+1;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    /*printf("\n%f",*((pm+l)+m->lado*k));*/ 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* ARRIBA A LA DERECHA. */ 

c8b_filtrom_ad(c,m) /* Arriba derecha. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=0;i<m->semilado;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=c->x-m->semilado;j<c->x;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-i;k<m->semilado+1;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-m->semilado;l<c->x-j;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* LISTàN IZQUIERDO. */ 

c8b_filtrom_i(c,m) /* Izquierda. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=m->semilado;i<c->y-m->semilado;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=0;j<m->semilado;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-m->semilado;k<m->semilado+1;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-j;l<m->semilado+1;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    /*printf("\n%f",*((pm+l)+m->lado*k));*/ 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* LISTàN DERECHO. */ 

c8b_filtrom_d(c,m) /* Derecha. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=m->semilado;i<c->y-m->semilado;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=c->x-m->semilado;j<c->x;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-m->semilado;k<m->semilado+1;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-m->semilado;l<c->x-j;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    /*printf("\n%f",*((pm+l)+m->lado*k));*/ 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

    /* ESQUINA INFERIOR IZQUIERDA. */ 

c8b_filtrom_bi(c,m) /* Abajo izquierda. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=c->y-m->semilado;i<c->y;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=0;j<m->semilado;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-m->semilado;k<c->y-i;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-j;l<m->semilado+1;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    /*printf("\n%f",*((pm+l)+m->lado*k));*/ 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* LISTàN INFERIOR. */ 

c8b_filtrom_b(c,m) /* Abajo. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=c->y-m->semilado;i<c->y;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=m->semilado;j<c->x-m->semilado;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-m->semilado;k<c->y-i;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-m->semilado;l<m->semilado+1;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

     /* ABAJO A LA DERECHA. */ 

c8b_filtrom_bd(c,m) /* Abajo derecha. */ 
canal8b *c; 
mascarar *m; 

int i,j,k,l; 
img8b **pce,**pcs; /* Puntero a la imagen entrante, a la imagen saliente, 
     a las tablas de entrada para las dos im genes. */ 
float cpix,superf; 
float *pm,*dir_cmas; 

pce=c->entra_ime; 
pcs=c->entra_ims; 
dir_cmas=m->ne+(int)(m->lado*m->lado/2); /* Punto central de la m scara. */ 
for (i=c->y-m->semilado;i<c->y;i++) { /* Recorre las filas. Eje Y.*/ 
 for (j=c->x-m->semilado;j<c->x;j++) { /* Recorre las columnas. Eje X. */ 
  for (superf=0,cpix=0,pm=dir_cmas,k=-m->semilado;k<c->y-i;k++) {/* Recorre las filas de la m scara. */ 
   for (l=-m->semilado;l<c->x-j;l++) {/* Recorre la columnas de la m scara. */ 
    cpix+=*((pm+l)+m->lado*k) * (float) *(*(pce+i+k)+j+l); 
    superf+=*((pm+l)+m->lado*k); 
    /*printf("\n%f",*((pm+l)+m->lado*k));*/ 
    } /* Recorre las columnas de una fila de la m scara. */ 
   } /* Recorre cada fila. */ 
   *(*(pcs+i)+j)=(img8b) (cpix/superf); 
  } /* Recorre cada columna de una fila de la imagen. */ 
 } /* Recorre cada fila de la imagen. */ 
return(1); 

/*----------------------------------------------*/ 
/* 
Ponemos la sombra como imagen canal activo para su visi¢n. 
Esto es mas r pido que copiar la imagen de la sombra en la entrante. 
*/ 

c8b_interces(c) 
canal8b *c; 

img8b *iswap,**dirswap; 

iswap=c->ims; 
c->ims=c->ime; 
c->ime=iswap; 

dirswap=c->entra_ims; 
c->entra_ims=c->entra_ime; 
c->entra_ime=dirswap; 

return(1); 

/*----------------------------------------------*/ 
/* La funci¢n de filtro devuelve la direcci¢n del canal filtrado. */ 
canal8b *c8b_filtramcanal(c,m) 
canal8b *c; 
mascarar *m; 

/* Filtramos el cuerpo central. */ 
c8b_filtrom_ai(c,m); /* Arriba izquierda.*/ 
c8b_filtrom_a(c,m); /* Arriba. */ 
c8b_filtrom_ad(c,m); /* Arriba derecha. */ 
c8b_filtrom_i(c,m); /* Izquierda. */ 
c8b_filtrom_d(c,m); /* Derecha. */ 
c8b_filtrom_bi(c,m); /* Abajo izquierda. */ 
c8b_filtrom_b(c,m); /* Abajo. */ 
c8b_filtrom_bd(c,m); /* Abajo derecha. */ 

c8b_filtrom_m(c,m); /** Filtra. */ 
c8b_interces(c); /** swap las dos im genes */ 
return(c); 

/* Entrada al filtro. */ 
c8b_filtra(im,m) 
c8b_imagen *im; 
mascarar m; 

int c; 

for (c=0;c<im->ncan;c++)   { 
    c8b_filtrac(im,m); 
    } 

 
 

 



 
Ir al raiz.
 
Ir al índice de temas.
 
Ir a los enlaces.